diff --git a/LICENCE b/LICENCE
index 49d1b85..86f3741 100644
--- a/LICENCE
+++ b/LICENCE
@@ -1,4 +1,4 @@
-MIT License
+MIT Licence
Copyright (c) 2026 OnixByte
diff --git a/docs/en-gb/_nav.json b/docs/en-gb/_nav.json
index 64b7c36..c810b93 100644
--- a/docs/en-gb/_nav.json
+++ b/docs/en-gb/_nav.json
@@ -1,14 +1,14 @@
[
- {
- "text": "blogs",
- "link": "/blogs/",
- "activeMatch": "/blogs/"
- },
{
"text": "projects",
"link": "/projects/",
"activeMatch": "/projects/"
},
+ {
+ "text": "blogs",
+ "link": "/blogs/",
+ "activeMatch": "/blogs/"
+ },
{
"text": "notifications",
"link": "/notifications/",
diff --git a/docs/en-gb/projects/calendar-toolbox/api.md b/docs/en-gb/projects/calendar-toolbox/api.md
new file mode 100644
index 0000000..f1da780
--- /dev/null
+++ b/docs/en-gb/projects/calendar-toolbox/api.md
@@ -0,0 +1,390 @@
+---
+title: Calendar Toolbox API
+---
+
+## Package Overview
+
+The library is organised under the base package `com.onixbyte.calendar` with the following structure:
+
+| Package | Description |
+|--------------------------------------------|--------------------------------------------|
+| `com.onixbyte.calendar` | Root calendar object |
+| `com.onixbyte.calendar.component` | iCalendar components (VEVENT, VTODO, etc.) |
+| `com.onixbyte.calendar.component.property` | Component-level properties |
+| `com.onixbyte.calendar.property` | Calendar-level properties |
+| `com.onixbyte.calendar.parameter` | iCalendar property parameters |
+| `com.onixbyte.calendar.recurrence` | Recurrence rule types |
+| `com.onixbyte.calendar.value` | Value types |
+| `com.onixbyte.calendar.util` | Formatting utilities |
+
+---
+
+## Calendar
+
+The top-level object representing an iCalendar (RFC 5545) VCALENDAR container.
+
+```java
+Calendar calendar = Calendar.builder()
+ .withCalendarScale(...)
+ .withMethod(...)
+ .withProductIdentifier(...)
+ .withVersion(...)
+ .withOwner(...)
+ .withPrimaryCalendar(...)
+ .withPublishedTTL(...)
+ .withCalendarDescription(...)
+ .withCalendarName(...)
+ .withCalendarId(...)
+ .withCustomProperties(...)
+ .withComponents(event, todo, ...)
+ .build();
+
+String icsContent = calendar.formatted();
+```
+
+### Calendar Properties
+
+All calendar-level properties live in `com.onixbyte.calendar.property` and implement `CalendarProperty`.
+
+| Class | iCalendar Property | Description |
+|--------------------------|----------------------|-------------------------------------------|
+| `CalendarScale` | `CALSCALE` | Calendar system (e.g., GREGORIAN) |
+| `Method` | `METHOD` | iCalendar method (e.g., PUBLISH, REQUEST) |
+| `ProductIdentifier` | `PRODID` | Product identifier of the calendar |
+| `Version` | `VERSION` | iCalendar version (e.g., 2.0) |
+| `Owner` | `X-OWNER` | Owner of the calendar |
+| `PrimaryCalendar` | `X-PRIMARY-CALENDAR` | Whether this is a primary calendar |
+| `PublishedTTL` | `X-PUBLISHED-TTL` | Time-to-live for published calendar |
+| `CalendarDescription` | `X-CALENDAR-DESC` | Calendar description |
+| `CalendarName` | `X-CALENDAR-NAME` | Calendar name |
+| `CalendarId` | `X-CALENDAR-ID` | Calendar identifier |
+| `CustomCalendarProperty` | `X-*` | Custom calendar properties |
+
+Custom properties are created using a builder:
+
+```java
+var customProp = CustomCalendarProperty.builder()
+ .withParameters(...)
+ .build("X-MY-PROPERTY", "my-value");
+```
+
+> Note: Custom property names **must** start with `X-`.
+
+---
+
+## Components
+
+Components represent the core entities in an iCalendar object. Each component implements `CalendarComponent` and is rendered between `BEGIN:TYPE` and `END:TYPE` delimiters.
+
+### Event (VEVENT)
+
+Represents a scheduled event.
+
+```java
+Event event = Event.builder()
+ .withDateTimeStamp(dtstamp) // required
+ .withUniqueIdentifier(uid) // required
+ .withDateTimeStart(dtstart)
+ .withDateTimeEnd(dtend) // mutually exclusive with duration
+ .withDuration(duration) // mutually exclusive with dtend
+ .withSummary(summary)
+ .withDescription(description)
+ .withClassification(classification)
+ .withDateTimeCreated(dateTimeCreated)
+ .withGeographicPosition(geoPos)
+ .withLastModified(lastModified)
+ .withLocation(location)
+ .withOrganiser(organiser)
+ .withPriority(priority)
+ .withSequenceNumber(seqNumber)
+ .withStatus(status)
+ .withTimeTransparency(transparency)
+ .withUniformResourceLocator(url)
+ .withRecurrenceId(recurrenceId)
+ .withRecurrenceRule(rrule)
+ .withAttachments(attachments)
+ .withAttendees(attendees)
+ .withCategories(categories)
+ .withComments(comments)
+ .withContacts(contacts)
+ .withExceptionDateTimes(exDates)
+ .withRequestStatuses(statuses)
+ .withRelated(related)
+ .withResources(resources)
+ .withRecurrenceDateTimes(rDates)
+ .build();
+```
+
+### Todo (VTODO)
+
+Represents a to-do item or task.
+
+```java
+Todo todo = Todo.builder()
+ .withDateTimeStamp(dtstamp) // required
+ .withUniqueIdentifier(uid) // required
+ .withSummary(summary)
+ .withDateTimeStart(dtstart)
+ .withDateTimeDue(due) // mutually exclusive with duration
+ .withDuration(duration) // mutually exclusive with due
+ .withDateTimeCompleted(completed)
+ .withPercentComplete(percent)
+ .withClassification(classification)
+ .withDateTimeCreated(created)
+ .withDescription(description)
+ .withGeographicPosition(geoPos)
+ .withLastModified(lastModified)
+ .withLocation(location)
+ .withOrganiser(organiser)
+ .withPriority(priority)
+ .withSequenceNumber(seq)
+ .withStatus(status)
+ .withRecurrenceId(recurId)
+ .withRecurrenceRule(rrule)
+ .withUniformResourceLocator(url)
+ .withAttachments(attachments)
+ .withAttendees(attendees)
+ .withCategories(categories)
+ .withComments(comments)
+ .withContacts(contacts)
+ .withExceptionDateTimes(exDates)
+ .withRequestStatuses(statuses)
+ .withRelatedToList(related)
+ .withResources(resources)
+ .withRecurrenceDateTimes(rDates)
+ .build();
+```
+
+### Journal (VJOURNAL)
+
+Represents a journal entry or diary note.
+
+```java
+Journal journal = Journal.builder()
+ .withDateTimeStamp(dtstamp) // required
+ .withUniqueIdentifier(uid) // required
+ .withSummary(summary)
+ .withClassification(classification)
+ .withDateTimeCreated(created)
+ .withDateTimeStart(dtstart)
+ .withLastModified(lastModified)
+ .withOrganiser(organiser)
+ .withRecurrenceId(recurId)
+ .withSequenceNumber(seq)
+ .withStatus(status)
+ .withUniformResourceLocator(url)
+ .withRecurrenceRule(rrule)
+ .withAttachments(attachments)
+ .withAttendees(attendees)
+ .withCategories(categories)
+ .withComments(comments)
+ .withContacts(contacts)
+ .withDescriptions(descriptions)
+ .withExceptionDateTimes(exDates)
+ .withRelatedToList(related)
+ .withRecurrenceDate(rDates)
+ .withRequestStatuses(statuses)
+ .build();
+```
+
+### FreeBusy (VFREEBUSY)
+
+Represents free/busy time information.
+
+```java
+FreeBusy freeBusy = FreeBusy.builder()
+ .withDateTimeStamp(dtstamp) // required
+ .withUniqueIdentifier(uid) // required
+ .withContact(contact)
+ .withDateTimeStart(dtstart)
+ .withDateTimeEnd(dtend)
+ .withOrganiser(organiser)
+ .withUniformResourceLocator(url)
+ .withAttendees(attendees)
+ .withComments(comments)
+ .withFreeBusyTimes(freeBusyTimes)
+ .withRequestStatuses(statuses)
+ .build();
+```
+
+### TimeZone (VTIMEZONE)
+
+Defines time zone rules including standard and daylight saving time transitions.
+
+```java
+TimeZone timezone = TimeZone.builder()
+ .withTimeZoneIdentifier(tzId)
+ .withLastModified(lastModified)
+ .withTimeZoneUrl(tzUrl)
+ .withTimeZoneProperties(standardProp, daylightProp)
+ .build();
+```
+
+Time zone properties define the actual transition rules:
+
+```java
+TimeZoneProperty standard = TimeZoneProperty.builder()
+ .withDateTimeStart(dtstart)
+ .withTimeZoneOffsetTo(offsetTo)
+ .withTimeZoneOffsetFrom(offsetFrom)
+ .withRecurrenceRule(rrule)
+ .withTimeZoneNames(tzName)
+ .buildStandard(); // or buildDaylight()
+
+TimeZoneProperty daylight = TimeZoneProperty.builder()
+ .withDateTimeStart(dtstart)
+ .withTimeZoneOffsetTo(offsetTo)
+ .withTimeZoneOffsetFrom(offsetFrom)
+ .buildDaylight();
+```
+
+### Alarm (VALARM)
+
+Defines alarm/reminder notifications. Three alarm types are supported:
+
+```java
+// Audio alarm
+Alarm audioAlarm = Alarm.builder()
+ .withTrigger(trigger)
+ .withDuration(duration)
+ .withRepeatCount(repeatCount)
+ .withAttachments(audioAttachment)
+ .buildAudio();
+
+// Display alarm
+Alarm displayAlarm = Alarm.builder()
+ .withTrigger(trigger)
+ .withDescription(description) // required
+ .withDuration(duration)
+ .withRepeatCount(repeatCount)
+ .buildDisplay();
+
+// Email alarm
+Alarm emailAlarm = Alarm.builder()
+ .withTrigger(trigger)
+ .withDescription(description) // required
+ .withSummary(summary) // required
+ .withAttendees(attendees) // required
+ .withDuration(duration)
+ .withRepeatCount(repeatCount)
+ .buildEmail();
+```
+
+---
+
+## Component Properties
+
+Component properties live in `com.onixbyte.calendar.component.property` and implement `ComponentProperty`.
+
+| Class | iCalendar Property | Description |
+|---------------------------|--------------------|----------------------------------------------------------|
+| `Action` | `ACTION` | Alarm action type (AUDIO, DISPLAY, EMAIL) |
+| `Attachment` | `ATTACH` | Document attachment |
+| `Attendee` | `ATTENDEE` | Event/task attendee |
+| `Categories` | `CATEGORIES` | Categories or tags |
+| `Classification` | `CLASS` | Access classification (PUBLIC, PRIVATE, CONFIDENTIAL) |
+| `Comment` | `COMMENT` | Comment |
+| `Contact` | `CONTACT` | Contact information |
+| `DateTimeCompleted` | `COMPLETED` | Completion date-time |
+| `DateTimeCreated` | `CREATED` | Creation date-time |
+| `DateTimeDue` | `DUE` | Due date-time |
+| `DateTimeEnd` | `DTEND` | End date-time |
+| `DateTimeStamp` | `DTSTAMP` | Date-time stamp |
+| `DateTimeStart` | `DTSTART` | Start date-time |
+| `Description` | `DESCRIPTION` | Description |
+| `ExceptionDateTimes` | `EXDATE` | Exception date-times |
+| `FreeBusyTime` | `FREEBUSY` | Free/busy time periods |
+| `GeographicPosition` | `GEO` | Geographic position (lat/long) |
+| `LastModified` | `LAST-MODIFIED` | Last modified date-time |
+| `Location` | `LOCATION` | Location |
+| `Organiser` | `ORGANIZER` | Event organiser |
+| `PercentComplete` | `PERCENT-COMPLETE` | Completion percentage |
+| `Priority` | `PRIORITY` | Priority level |
+| `RecurrenceDateTimes` | `RDATE` | Recurrence date-times |
+| `RecurrenceId` | `RECURRENCE-ID` | Recurrence instance identifier |
+| `RecurrenceRule` | `RRULE` | Recurrence rule |
+| `RelatedTo` | `RELATED-TO` | Related component reference |
+| `RepeatCount` | `REPEAT` | Alarm repeat count |
+| `RequestStatus` | `REQUEST-STATUS` | Request status |
+| `Resources` | `RESOURCES` | Resources |
+| `SequenceNumber` | `SEQUENCE` | Sequence number (revision) |
+| `Status` | `STATUS` | Component status (TENTATIVE, CONFIRMED, CANCELLED, etc.) |
+| `Summary` | `SUMMARY` | Title or summary |
+| `TimeTransparency` | `TRANSP` | Time transparency (OPAQUE, TRANSPARENT) |
+| `TimeZoneIdentifier` | `TZID` | Time zone identifier |
+| `TimeZoneName` | `TZNAME` | Time zone name |
+| `TimeZoneOffsetFrom` | `TZOFFSETFROM` | Time zone offset from UTC |
+| `TimeZoneOffsetTo` | `TZOFFSETTO` | Time zone offset to UTC |
+| `TimeZoneUrl` | `TZURL` | Time zone URL |
+| `Trigger` | `TRIGGER` | Alarm trigger |
+| `UniformResourceLocator` | `URL` | Associated URL |
+| `UniqueIdentifier` | `UID` | Unique identifier |
+| `CustomComponentProperty` | `X-*` | Custom component properties |
+
+---
+
+## Parameters
+
+Parameters in `com.onixbyte.calendar.parameter` provide additional qualifiers on component properties.
+
+| Class | iCalendar Parameter | Description |
+|-------------------------------|---------------------|--------------------------------------------------------|
+| `AlarmTriggerRelationship` | `RELATED` | Trigger relationship (START, END) |
+| `AlternateTextRepresentation` | `ALTREP` | Alternate text URI |
+| `CalendarUserType` | `CUTYPE` | Calendar user type (INDIVIDUAL, GROUP, RESOURCE, etc.) |
+| `CommonName` | `CN` | Common name |
+| `Delegatees` | `DELEGATED-TO` | Delegatees |
+| `Delegators` | `DELEGATED-FROM` | Delegators |
+| `DirectoryEntryReference` | `DIR` | Directory entry URI |
+| `FormatType` | `FMTTYPE` | Format type (MIME type) |
+| `FreeBusyTimeType` | `FBTYPE` | Free/busy time type |
+| `InlineEncoding` | `ENCODING` | Inline encoding (BASE64) |
+| `Language` | `LANGUAGE` | Language |
+| `Membership` | `MEMBER` | Group membership |
+| `ParticipationRole` | `ROLE` | Participation role (CHAIR, REQ-PARTICIPANT, etc.) |
+| `ParticipationStatus` | `PARTSTAT` | Participation status (ACCEPTED, DECLINED, etc.) |
+| `RecurrenceIdentifierRange` | `RANGE` | Recurrence range (THISANDPRIOR, THISANDFUTURE) |
+| `RelationshipType` | `RELTYPE` | Relationship type (PARENT, CHILD, SIBLING) |
+| `RsvpExpectation` | `RSVP` | RSVP expectation (TRUE, FALSE) |
+| `SentBy` | `SENT-BY` | Sent by |
+| `TimeZoneIdentifier` | `TZID` | Time zone identifier |
+| `ValueDataType` | `VALUE` | Value data type (DATE, DATE-TIME, etc.) |
+
+---
+
+## Recurrence Types
+
+Located in `com.onixbyte.calendar.recurrence`.
+
+| Class | Description |
+|--------------|---------------------------------------------------------------------------|
+| `Frequency` | Frequency constants (DAILY, WEEKLY, MONTHLY, YEARLY) for recurrence rules |
+| `WeekdayNum` | Weekday number for recurrence rules (e.g., 2nd Monday) |
+
+---
+
+## Value Types
+
+Located in `com.onixbyte.calendar.value`.
+
+| Class | Description |
+|---------------------|------------------------------------------------|
+| `FreeBusyTimeValue` | Represents free/busy time value |
+| `PeriodOfTime` | Represents a period of time with start and end |
+| `PropertyValue` | Base value type for properties |
+| `UtcOffset` | UTC offset value (e.g., `-05:00`, `+01:00`) |
+
+---
+
+## Formatted Output
+
+All components and properties provide a `formatted()` method that returns an iCalendar-compliant string representation. The `Calendar.formatted()` method produces a complete `.ics` output wrapped in `BEGIN:VCALENDAR`/`END:VCALENDAR`.
+
+```java
+String ics = calendar.formatted();
+// BEGIN:VCALENDAR
+// CALSCALE:GREGORIAN
+// METHOD:PUBLISH
+// ...
+// END:VCALENDAR
+```
diff --git a/docs/en-gb/projects/calendar-toolbox/index.mdx b/docs/en-gb/projects/calendar-toolbox/index.mdx
new file mode 100644
index 0000000..0b3799e
--- /dev/null
+++ b/docs/en-gb/projects/calendar-toolbox/index.mdx
@@ -0,0 +1,102 @@
+---
+title: Calendar Toolbox
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## Introduction
+
+Calendar Toolbox is a Java library designed to simplify the creation of `.ics` files, adhering to the iCalendar specification (RFC 5545). This library provides developers with a straightforward API to generate calendar events that can be imported into popular calendar applications such as Microsoft Outlook, Google Calendar, and Apple Calendar.
+
+With Calendar Toolbox, you can effortlessly create, customise, and export calendar event files programmatically, enabling integration of calendar functionalities into your Java applications with minimal effort.
+
+## Features
+
+- **Full RFC 5545 Compliance** — Supports standard iCalendar components including VEVENT, VTODO, VJOURNAL, VFREEBUSY, VTIMEZONE, and VALARM.
+- **Fluent Builder Pattern** — All components and properties use builder pattern for readable and intuitive construction.
+- **Type-Safe Properties** — Strongly typed properties and parameters ensure correctness at compile time.
+- **Custom Extensions** — Support for custom `X-` properties at both calendar and component level.
+- **Lightweight** — Zero external dependencies for core functionality.
+
+## Installation
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:calendar-toolbox:1.1.0")
+ }
+ ```
+
+
+ ```xml title="pom.xml"
+
+
+ com.onixbyte
+ calendar-toolbox
+ 1.1.0
+
+
+ ```
+
+
+
+## Quick Start
+
+```java
+import com.onixbyte.calendar.Calendar;
+import com.onixbyte.calendar.component.Event;
+import com.onixbyte.calendar.component.property.*;
+import com.onixbyte.calendar.property.*;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+public class CalendarExample {
+
+ public static void main(String[] args) {
+ // Create required date-time properties
+ var now = ZonedDateTime.now(ZoneOffset.UTC);
+ var dtstamp = DateTimeStamp.of(now);
+ var uid = UniqueIdentifier.of("meeting-001@example.com");
+ var dtstart = DateTimeStart.of(
+ LocalDateTime.of(2025, 8, 15, 9, 0),
+ "America/New_York"
+ );
+ var dtend = DateTimeEnd.of(
+ LocalDateTime.of(2025, 8, 15, 10, 0),
+ "America/New_York"
+ );
+ var summary = Summary.of("Team Standup");
+ var description = Description.of("Daily team standup meeting.");
+
+ // Build the event
+ var event = Event.builder()
+ .withDateTimeStamp(dtstamp)
+ .withUniqueIdentifier(uid)
+ .withDateTimeStart(dtstart)
+ .withDateTimeEnd(dtend)
+ .withSummary(summary)
+ .withDescription(description)
+ .build();
+
+ // Build the calendar and output .ics content
+ var calendar = Calendar.builder()
+ .withCalendarScale(CalendarScale.of("GREGORIAN"))
+ .withMethod(Method.of("PUBLISH"))
+ .withProductIdentifier(ProductIdentifier.of("-//OnixByte//Calendar Toolbox//EN"))
+ .withVersion(Version.of("2.0"))
+ .withComponents(event)
+ .build();
+
+ System.out.println(calendar.formatted());
+ }
+}
+```
+
+This produces an `.ics` string that can be saved to a file or sent via email.
+
+## License
+
+Calendar Toolbox is open-source software released under the MIT License.
diff --git a/docs/en-gb/projects/captcha/api.md b/docs/en-gb/projects/captcha/api.md
new file mode 100644
index 0000000..40498f5
--- /dev/null
+++ b/docs/en-gb/projects/captcha/api.md
@@ -0,0 +1,248 @@
+---
+title: Captcha API
+---
+
+## Package Overview
+
+The library is organised under the base package `com.onixbyte.captcha` with the following structure:
+
+| Package | Description |
+|---------------------------------------------|---------------------------------------|
+| `com.onixbyte.captcha` | Core interfaces |
+| `com.onixbyte.captcha.impl` | Default implementations |
+| `com.onixbyte.captcha.text` | Text producer and renderer interfaces |
+| `com.onixbyte.captcha.text.impl` | Text producer and renderer impls |
+| `com.onixbyte.captcha.text.enums` | Text-related enums |
+| `com.onixbyte.captcha.background` | Background producer interface |
+| `com.onixbyte.captcha.background.impl` | Background producer implementations |
+| `com.onixbyte.captcha.noise` | Noise producer interface |
+| `com.onixbyte.captcha.noise.impl` | Noise producer implementations |
+| `com.onixbyte.captcha.gimpy` | Distortion engine interface |
+| `com.onixbyte.captcha.gimpy.impl` | Distortion engine implementations |
+
+---
+
+## Producer
+
+The top-level interface responsible for creating CAPTCHA images with text drawn on them.
+
+```java
+Producer captcha = DefaultCaptchaProducer.builder()
+ .textProducer(textProducer)
+ .wordRenderer(wordRenderer)
+ .gimpyEngine(gimpyEngine)
+ .backgroundProducer(backgroundProducer)
+ .width(200)
+ .height(50)
+ .borderDrawn(true)
+ .borderColour(Color.BLACK)
+ .borderThickness(1)
+ .build();
+
+String text = captcha.createText();
+BufferedImage image = captcha.createImage(text);
+```
+
+### DefaultCaptchaProducer Builder
+
+| Method | Default Value | Description |
+|---------------------|---------------------------------------------|---------------------------------------|
+| `textProducer` | `DefaultTextProducer.builder().build()` | The text producer to use |
+| `wordRenderer` | `DefaultWordRenderer.builder().build()` | The word renderer to use |
+| `gimpyEngine` | `WaterRipple.builder().build()` | The distortion engine to use |
+| `backgroundProducer`| `DefaultBackgroundProducer.builder().build()`| The background producer to use |
+| `width` | `200` | Width of the CAPTCHA image |
+| `height` | `50` | Height of the CAPTCHA image |
+| `borderDrawn` | `true` | Whether a border is drawn |
+| `borderColour` | `Color.BLACK` | The colour of the border |
+| `borderThickness` | `1` | The thickness of the border |
+
+---
+
+## Text
+
+### TextProducer
+
+Interface for creating CAPTCHA text strings.
+
+```java
+public interface TextProducer {
+ String getText();
+}
+```
+
+#### DefaultTextProducer
+
+Generates random text with configurable length and character set.
+
+```java
+DefaultTextProducer textProducer = DefaultTextProducer.builder()
+ .length(6) // default: 6
+ .chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) // default: a-z, A-Z, 0-9
+ .build();
+```
+
+| Method | Default Value | Description |
+|----------|-----------------------------------------------------------|--------------------------------|
+| `length` | `6` | Length of generated text |
+| `chars` | `a-z`, `A-Z`, `0-9` (62 characters) | Characters used for generation |
+
+### WordRenderer
+
+Interface for rendering text onto an image.
+
+```java
+public interface WordRenderer {
+ BufferedImage renderWord(String word, int width, int height);
+}
+```
+
+#### DefaultWordRenderer
+
+Renders text with configurable font, colour, and spacing.
+
+```java
+DefaultWordRenderer wordRenderer = DefaultWordRenderer.builder()
+ .fontSize(40) // default: 40
+ .fonts("Arial", "Courier") // default: Arial, Courier
+ .fontColour(Color.BLACK) // default: Color.BLACK
+ .charSpace(2) // default: 2
+ .fontStyle(FontStyle.BOLD) // default: FontStyle.BOLD
+ .build();
+```
+
+| Method | Default Value | Description |
+|-------------|-----------------------------------|-----------------------------------------|
+| `fontSize` | `40` | Font size in pixels |
+| `fonts` | `["Arial", "Courier"]` | Font families to use (randomly chosen) |
+| `fontColour`| `Color.BLACK` | Font colour |
+| `charSpace` | `2` | Space between characters in pixels |
+| `fontStyle` | `FontStyle.BOLD` | Font style to apply |
+
+### FontStyle
+
+Defines the supported font styles for rendering CAPTCHA text.
+
+| Value | Corresponding AWT Constant | Description |
+|---------------|-------------------------------------|------------------------------|
+| `PLAIN` | `java.awt.Font.PLAIN` | Plain style |
+| `BOLD` | `java.awt.Font.BOLD` | Bold style |
+| `ITALIC` | `java.awt.Font.ITALIC` | Italic style |
+| `BOLD_ITALIC` | `java.awt.Font.BOLD | Font.ITALIC` | Bold and italic combined |
+
+---
+
+## GimpyEngine
+
+Interface for applying image distortion effects.
+
+```java
+public interface GimpyEngine {
+ BufferedImage getDistortedImage(BufferedImage baseImage);
+}
+```
+
+### WaterRipple
+
+Applies a water ripple distortion effect. Extends `AbstractGimpyEngine` and adds noise automatically.
+
+```java
+WaterRipple gimpy = WaterRipple.builder()
+ .noiseProducer(DefaultNoiseProducer.builder().build()) // default: DefaultNoiseProducer
+ .build();
+```
+
+| Method | Default Value | Description |
+|-----------------|---------------------------------------------|------------------------------|
+| `noiseProducer` | `DefaultNoiseProducer.builder().build()` | The noise producer to use |
+
+### FishEyeGimpy
+
+Applies a fish-eye distortion effect with horizontal and vertical lines over the image.
+
+```java
+FishEyeGimpy gimpy = FishEyeGimpy.builder()
+ .build();
+```
+
+### ShadowGimpy
+
+Applies a shadow and ripple effect. Extends `AbstractGimpyEngine` and adds noise automatically.
+
+```java
+ShadowGimpy gimpy = ShadowGimpy.builder()
+ .noiseProducer(DefaultNoiseProducer.builder().build()) // default: DefaultNoiseProducer
+ .build();
+```
+
+| Method | Default Value | Description |
+|-----------------|---------------------------------------------|------------------------------|
+| `noiseProducer` | `DefaultNoiseProducer.builder().build()` | The noise producer to use |
+
+---
+
+## Noise
+
+### NoiseProducer
+
+Interface for adding noise to an image.
+
+```java
+public interface NoiseProducer {
+ void makeNoise(BufferedImage image, float factorOne, float factorTwo,
+ float factorThree, float factorFour);
+}
+```
+
+#### DefaultNoiseProducer
+
+Adds noise curves with configurable colour.
+
+```java
+DefaultNoiseProducer noise = DefaultNoiseProducer.builder()
+ .noiseColour(Color.BLACK) // default: Color.BLACK
+ .build();
+```
+
+| Method | Default Value | Description |
+|---------------|---------------|---------------------|
+| `noiseColour` | `Color.BLACK` | The noise colour |
+
+#### NoNoiseProducer
+
+A no-op implementation that does not add any noise to the image.
+
+```java
+NoiseProducer noise = NoNoiseProducer.builder()
+ .build();
+```
+
+---
+
+## Background
+
+### BackgroundProducer
+
+Interface for adding background to an image.
+
+```java
+public interface BackgroundProducer {
+ BufferedImage addBackground(BufferedImage image);
+}
+```
+
+#### DefaultBackgroundProducer
+
+Creates a gradient background with configurable start and end colours.
+
+```java
+DefaultBackgroundProducer background = DefaultBackgroundProducer.builder()
+ .colourFrom(Color.WHITE) // default: Color.LIGHT_GRAY
+ .colourTo(Color.LIGHT_GRAY) // default: Color.WHITE
+ .build();
+```
+
+| Method | Default Value | Description |
+|--------------|--------------------|---------------------------------|
+| `colourFrom` | `Color.LIGHT_GRAY` | The starting colour of gradient |
+| `colourTo` | `Color.WHITE` | The ending colour of gradient |
diff --git a/docs/en-gb/projects/captcha/index.mdx b/docs/en-gb/projects/captcha/index.mdx
new file mode 100644
index 0000000..b2d29b0
--- /dev/null
+++ b/docs/en-gb/projects/captcha/index.mdx
@@ -0,0 +1,89 @@
+---
+title: Captcha
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## Introduction
+
+Captcha is a Java library for generating CAPTCHA images. This project is a spiritual successor to Google's Kaptcha, modernised for contemporary development practices.
+
+With Captcha, you can easily generate customisable CAPTCHA images with various distortion effects, noise, and background options to integrate into your Java applications.
+
+## Features
+
+- **Easy Integration** — Simple builder-based API for quick setup and configuration.
+- **Customisable CAPTCHA Generation** — Configure text length, character sets, font styles, and colours.
+- **Multiple Distortion Effects** — Choose from Water Ripple, Fish Eye, and Shadow effects.
+- **Configurable Noise** — Add noise lines with custom colours, or disable noise entirely.
+- **Gradient Backgrounds** — Customisable gradient background colours.
+- **Clean, Modern Codebase** — Well-documented, type-safe, and easy to extend.
+
+## Installation
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:captcha:1.0.0")
+ }
+ ```
+
+
+ ```xml title="pom.xml"
+
+
+ com.onixbyte
+ captcha
+ 1.0.0
+
+
+ ```
+
+
+
+## Quick Start
+
+```java
+import com.onixbyte.captcha.Producer;
+import com.onixbyte.captcha.background.BackgroundProducer;
+import com.onixbyte.captcha.background.impl.DefaultBackgroundProducer;
+import com.onixbyte.captcha.gimpy.GimpyEngine;
+import com.onixbyte.captcha.gimpy.impl.WaterRipple;
+import com.onixbyte.captcha.impl.DefaultCaptchaProducer;
+import com.onixbyte.captcha.noise.NoiseProducer;
+import com.onixbyte.captcha.noise.impl.DefaultNoiseProducer;
+import com.onixbyte.captcha.text.TextProducer;
+import com.onixbyte.captcha.text.WordRenderer;
+import com.onixbyte.captcha.text.impl.DefaultTextProducer;
+import com.onixbyte.captcha.text.impl.DefaultWordRenderer;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+public class CaptchaExample {
+
+ public static void main(String[] args) throws IOException {
+ // Create a CAPTCHA producer with default configurations
+ Producer captcha = DefaultCaptchaProducer.builder().build();
+
+ // Generate text and create the image
+ String captchaText = captcha.createText();
+ BufferedImage captchaImage = captcha.createImage(captchaText);
+
+ // Save the image to a file
+ ImageIO.write(captchaImage, "png", new File("captcha.png"));
+
+ System.out.println("CAPTCHA text: " + captchaText);
+ }
+}
+```
+
+This generates a CAPTCHA image with a 6-character random text and saves it as a PNG file.
+
+## License
+
+Captcha is open-source software released under the MIT License.
diff --git a/docs/en-gb/projects/delta-force-guide/api.md b/docs/en-gb/projects/delta-force-guide/api.md
new file mode 100644
index 0000000..13eb5b6
--- /dev/null
+++ b/docs/en-gb/projects/delta-force-guide/api.md
@@ -0,0 +1,91 @@
+---
+title: Delta Force Guide API
+---
+
+## Backend API Overview
+
+The backend is a Spring Boot 3 application organised under the base package `com.onixbyte.deltaforceguide`:
+
+| Package | Description |
+|---------------------------------------------|-----------------------------------|
+| `controller` | REST API endpoint controllers |
+| `service` | Business logic layer |
+| `repository` | MyBatis data access layer |
+| `domain` | JPA entity and domain objects |
+| `config` | Spring configuration (security, cache, etc.) |
+| `properties` | Configuration property classes |
+| `enumeration` | Enumerated types |
+| `shared` | Shared utilities |
+
+## API Endpoints
+
+### Authentication
+
+| Method | Path | Description | Auth |
+|--------|-----------------------|--------------------------|------|
+| `POST` | `/api/auth/login` | Log in with credentials | No |
+| `POST` | `/api/auth/refresh` | Refresh access token | No |
+| `GET` | `/api/auth/profile` | Get current user profile | Yes |
+
+### Firearms
+
+| Method | Path | Description |
+|----------|-----------------------|--------------------------|
+| `GET` | `/api/firearms` | List firearms (paginated, filterable by type) |
+| `GET` | `/api/firearms/:id` | Get firearm by ID |
+| `POST` | `/api/firearms` | Create a new firearm |
+| `PUT` | `/api/firearms/:id` | Update an existing firearm |
+| `DELETE` | `/api/firearms/:id` | Remove a firearm |
+
+### Modifications
+
+| Method | Path | Description |
+|----------|-----------------------------------|--------------------------------|
+| `GET` | `/api/modifications` | List modifications (paginated, filterable by firearm and tags) |
+| `GET` | `/api/modifications/:id` | Get modification by ID |
+| `POST` | `/api/modifications` | Create a modification |
+| `POST` | `/api/modifications/batch` | Batch create modifications |
+| `PUT` | `/api/modifications/:id` | Update a modification |
+| `DELETE` | `/api/modifications/:id` | Remove a modification |
+| `DELETE` | `/api/modifications/batch-delete` | Batch remove modifications |
+
+### Tags
+
+| Method | Path | Description |
+|--------|-----------------------|-----------------------|
+| `GET` | `/api/tags` | List all tags |
+
+## Frontend Routes
+
+| Path | Layout | Page | Description |
+|---------------|-------------|-------------------|---------------------------------|
+| `/` | Hero Layout | Firearms Browser | Home page — firearm list |
+| `/firearms` | Hero Layout | Firearms Browser | Firearm detail and search |
+| `/mod-codes` | Hero Layout | Modification Codes| Modification code library |
+| `/legal` | Hero Layout | Legal | Legal and privacy information |
+| `/login` | Empty Layout| Login | User authentication page |
+
+## Frontend State Management
+
+Redux Toolkit with Redux Persist manages:
+
+- **Auth state** — Access tokens, refresh tokens, user profile
+- **Settings state** — User preferences persisted to local storage
+
+## API Client
+
+The frontend uses a shared `WebClient` wrapper around Axios that handles:
+
+- Base URL configuration (pointing to the backend API)
+- JWT access token injection via request interceptors
+- Automatic token refresh on 401 responses
+
+## Infrastructure
+
+| Component | Technology |
+|---------------|-----------------------------|
+| Database | PostgreSQL (with Flyway migrations) |
+| Cache | Redis (session/token storage) |
+| File Storage | AWS S3 (firearm images) |
+| Containerisation | Docker |
+| Deployment | Docker Compose behind Nginx |
diff --git a/docs/en-gb/projects/delta-force-guide/index.mdx b/docs/en-gb/projects/delta-force-guide/index.mdx
new file mode 100644
index 0000000..c5e9e11
--- /dev/null
+++ b/docs/en-gb/projects/delta-force-guide/index.mdx
@@ -0,0 +1,46 @@
+---
+title: Delta Force Guide
+---
+
+## Introduction
+
+Delta Force Guide is a full-stack web application providing a searchable library of firearm modification codes for the game Delta Force. It consists of two components:
+
+- **Web Frontend** — A React-based SPA for browsing, filtering, and copying modification codes.
+- **Backend Server** — A Spring Boot REST API handling data persistence, authentication, and content management.
+
+The live site is available at **[dfguide.onixbyte.cn](https://dfguide.onixbyte.cn)**.
+
+## Features
+
+- **Firearm Browser** — Browse a curated list of in-game firearms with detailed stats.
+- **Modification Code Library** — Search and filter modification codes by weapon, mode, and tags.
+- **One-Click Copy** — Copy modification codes directly from the interface.
+- **Efficient Rendering** — Large lists rendered smoothly with window virtualisation.
+- **Authentication** — User login with JWT-based auth and CAPTCHA verification.
+- **Admin Panel** — Full CRUD operations for firearms and modification data.
+- **Static-Friendly** — Frontend deployed as a static site with API proxy.
+
+## Architecture
+
+| Component | Tech Stack |
+|---------------|---------------------------------------------------------------|
+| **Frontend** | React 19, TypeScript, Tailwind CSS 4, Ant Design 6, React Router 7, Redux Toolkit, TanStack Virtual |
+| **Backend** | Spring Boot 3, Java 21, PostgreSQL, MyBatis, Flyway, Redis |
+| **Auth** | JWT (access + refresh tokens), CAPTCHA integration |
+| **Storage** | AWS S3 for image uploads |
+
+The frontend is a static site served by Vite, communicating with the Spring Boot REST API backend. Authentication uses JWT access and refresh tokens with Redis-backed refresh token management.
+
+## Repositories
+
+- [delta-force-guide-server](https://github.com/onixbyte/delta-force-guide-server) — Spring Boot backend
+- [delta-force-guide-web](https://github.com/onixbyte/delta-force-guide-web) — React frontend
+
+## Quick Links
+
+- **Live Site:** [dfguide.onixbyte.cn](https://dfguide.onixbyte.cn)
+
+## License
+
+Delta Force Guide is open-source software released under the MIT Licence.
diff --git a/docs/en-gb/projects/helix/index.mdx b/docs/en-gb/projects/helix/index.mdx
new file mode 100644
index 0000000..d3c4c51
--- /dev/null
+++ b/docs/en-gb/projects/helix/index.mdx
@@ -0,0 +1,71 @@
+---
+title: Helix
+---
+
+## Introduction
+
+Helix is a full-stack enterprise application template designed to accelerate the development of production-grade business applications. It provides a pre-built foundation with all the essential features an enterprise application needs, allowing teams to focus on business logic rather than infrastructure.
+
+The project consists of two components:
+
+- **Helix Server** — A Spring Boot backend providing REST APIs, authentication, authorisation, and data management.
+- **Helix Web** — A React-based SPA frontend with a modern UI, role-based routing, and enterprise identity integration.
+
+Helix is intended to be used as a starting point. Fork or clone it and begin building your own domain-specific features on top of the ready-made foundation.
+
+## Features
+
+### Backend (Helix Server)
+
+- **Authentication & Authorisation** — JWT-based access and refresh token flow with Spring Security. Supports Microsoft Entra ID (Azure AD) integration.
+- **Role-Based Access Control** — Fine-grained permissions via roles, authorities, and menu-level access control.
+- **User & Organisation Management** — Full CRUD for users, departments, positions, and roles.
+- **Menu Management** — Hierarchical menu tree with configurable visibility per role.
+- **Asset Management** — File uploads to AWS S3 with CDN-ready prefix handling.
+- **Settings Management** — Typed application settings persisted to database.
+- **Captcha Integration** — Image CAPTCHA verification for login and registration flows.
+- **Redis Caching** — High-performance caching with configurable TTL and custom serialisers.
+- **Data Access** — Hybrid persistence with Spring Data JPA and MyBatis.
+- **Validation** — Bean Validation groups with custom validation constraints.
+
+### Frontend (Helix Web)
+
+- **Enterprise Identity** — Microsoft Entra ID login via MSAL. Extensible social login provider architecture (Microsoft, Google, GitLab, Slack, Discord, DingTalk, Lark, WeCom, email/password).
+- **Dashboard Layout** — Responsive admin dashboard with collapsible sidebar and role-based menu rendering.
+- **User Management** — Data table with search, pagination, add/edit dialogues, role assignment, and phone number validation.
+- **Role & Menu Management** — Role CRUD with authority assignment. Tree-based menu configuration.
+- **Department & Position** — Organisation hierarchy management interfaces.
+- **Protected Routing** — Route guards checking authentication and authorisation before page load.
+- **State Management** — Redux Toolkit with Redux Persist for auth token persistence.
+- **HTTP Client** — Axios wrapper with automatic JWT token injection and 401 refresh handling.
+
+## Architecture
+
+| Layer | Technology |
+|--------------|---------------------------------------------------------------|
+| **Frontend** | React 19, TypeScript, Tailwind CSS 4, Ant Design 6, React Router 7, Redux Toolkit, Axios, MSAL |
+| **Backend** | Spring Boot 3.5, Java 17, Spring Security, MyBatis, Spring Data JPA |
+| **Database** | PostgreSQL (with Flyway migrations) |
+| **Cache** | Redis (session/token storage) |
+| **Storage** | AWS S3 (asset uploads) |
+
+The frontend communicates with the backend via a RESTful JSON API. Authentication flow uses JWT access tokens (short-lived) with refresh tokens stored in Redis. Microsoft Entra ID integration is handled client-side via MSAL and validated server-side.
+
+## Repositories
+
+- [helix-server](https://git.onixbyte.cn/helix/helix-server) — Spring Boot backend
+- [helix-web](https://git.onixbyte.cn/helix/helix-web) — React frontend
+
+## Getting Started
+
+Helix is designed as a template project. To start a new project:
+
+1. Fork or clone both `helix-server` and `helix-web` repositories.
+2. Configure your database, Redis, and S3 settings in the backend.
+3. Configure your authentication providers and API base URL in the frontend.
+4. Run the backend: `./gradlew bootRun`
+5. Run the frontend: `pnpm install && pnpm dev`
+
+## License
+
+Helix is open-source software released under the MIT License.
diff --git a/docs/en-gb/projects/index.md b/docs/en-gb/projects/index.md
new file mode 100644
index 0000000..8becd7e
--- /dev/null
+++ b/docs/en-gb/projects/index.md
@@ -0,0 +1,21 @@
+---
+title: Projects
+---
+
+Explore open-source projects developed by OnixByte.
+
+## Libraries & Toolkits
+
+- **[OnixByte Toolbox](/projects/onixbyte-toolbox)** — A development kit for Java applications: AES, hashing, Base64, collection utilities, crypto key loaders, statistical calculators, identity generators, and generic tuples.
+- **[regions4j](/projects/regions4j)** — Type-safe ISO 3166-1 regional metadata as a Java enum with O(1) lookups, E.164 dialling codes, and locale tags.
+- **[Captcha](/projects/captcha)** — A modern Java CAPTCHA generation library with water ripple, fish-eye, and shadow distortion effects.
+- **[Calendar Toolbox](/projects/calendar-toolbox)** — A Java library for creating `.ics` files conforming to the iCalendar specification (RFC 5545).
+
+## Full-Stack Applications
+
+- **[Helix](/projects/helix)** — An enterprise application template with Spring Boot backend and React frontend, featuring JWT auth, RBAC, user and organisation management, and Microsoft Entra ID integration.
+- **[Delta Force Guide](/projects/delta-force-guide)** — A web app providing a searchable library of firearm modification codes for the game _Delta Force: Havvk Ops_, with a React SPA and Spring Boot REST API.
+
+## Vite Plugins
+
+- **[Port Checker](/projects/vite-plugins/port-checker)** — Warns when the Vite dev server listens on a browser-restricted port, preventing silent connection failures.
diff --git a/docs/en-gb/projects/onixbyte-toolbox/api.md b/docs/en-gb/projects/onixbyte-toolbox/api.md
new file mode 100644
index 0000000..c097076
--- /dev/null
+++ b/docs/en-gb/projects/onixbyte-toolbox/api.md
@@ -0,0 +1,209 @@
+---
+title: OnixByte Toolbox API
+---
+
+## Package Overview
+
+All modules are published under the `com.onixbyte` group ID. Each module has its own base package:
+
+| Module | Maven Artifact | Base Package |
+|----------------------|------------------------|---------------------------------------|
+| Common Toolbox | `common-toolbox` | `com.onixbyte.common` |
+| Crypto Toolbox | `crypto-toolbox` | `com.onixbyte.crypto` |
+| Math Toolbox | `math-toolbox` | `com.onixbyte.math` |
+| Tuple | `tuple` | `com.onixbyte.tuple` |
+| Identity Generator | `identity-generator` | `com.onixbyte.identitygenerator` |
+
+---
+
+## Common Toolbox
+
+### Adapter
+
+`ObjectMapAdapter` — Converts between objects and maps. Useful for serialisation or data transformation scenarios where key-value representations are preferred.
+
+```java
+import com.onixbyte.common.adapter.ObjectMapAdapter;
+```
+
+### Utility Classes
+
+| Class | Description |
+|--------------------|----------------------------------------------------------|
+| `AesUtil` | AES symmetric encryption/decryption with key generation |
+| `Base64Util` | Base64 encoding and decoding with multiple charset support|
+| `BoolUtil` | Boolean parsing and conversion utilities |
+| `BranchUtil` | Conditional branching helpers with functional-style chains|
+| `CollectionUtil` | Collection manipulation — grouping, partitioning, merging |
+| `HashUtil` | Hashing utilities supporting MD5, SHA-1, SHA-256, SHA-512 |
+| `MapUtil` | Map builder, merge, and transformation helpers |
+| `RangeUtil` | Numeric range operations with boundary handling |
+
+**AesUtil Example:**
+
+```java
+var key = AesUtil.generateKey();
+var encrypted = AesUtil.encrypt("hello world", key);
+var decrypted = AesUtil.decrypt(encrypted, key);
+```
+
+**HashUtil Example:**
+
+```java
+var md5 = HashUtil.md5("hello world");
+var sha256 = HashUtil.sha256("hello world");
+var fileSha = HashUtil.sha256(new File("data.bin"));
+```
+
+**CollectionUtil Example:**
+
+```java
+var partitioned = CollectionUtil.partition(list, 100);
+var grouped = CollectionUtil.groupBy(users, User::getDepartment);
+```
+
+---
+
+## Crypto Toolbox
+
+Provides a clean abstraction for loading cryptographic keys in PEM format. Supports both RSA and ECDSA algorithms.
+
+### Key Loaders
+
+| Class | Description |
+|---------------------------|--------------------------------------------|
+| `RSAPrivateKeyLoader` | Load RSA private keys from PEM strings |
+| `RSAPublicKeyLoader` | Load RSA public keys from PEM strings |
+| `ECPrivateKeyLoader` | Load ECDSA private keys from PEM strings |
+| `ECPublicKeyLoader` | Load ECDSA public keys from PEM strings |
+
+All key loaders implement either `PrivateKeyLoader` or `PublicKeyLoader` interfaces.
+
+**RSA Example:**
+
+```java
+var privateKey = new RSAPrivateKeyLoader().load(pemString);
+var publicKey = new RSAPublicKeyLoader().load(pemString);
+```
+
+**ECDSA Example:**
+
+```java
+var ecPrivateKey = new ECPrivateKeyLoader().load(pemString);
+var ecPublicKey = new ECPublicKeyLoader().load(pemString);
+```
+
+### Utility
+
+`CryptoUtil` — Provides convenient methods for digital signature creation and verification, as well as general-purpose cryptographic helpers.
+
+### Exceptions
+
+| Class | Description |
+|------------------------|---------------------------------------------------|
+| `KeyLoadingException` | Thrown when a PEM-formatted key fails to parse |
+
+---
+
+## Math Toolbox
+
+Statistical computation utilities for working with numeric datasets.
+
+### Core Classes
+
+| Class | Description |
+|-------------------------|----------------------------------------------------------|
+| `Calculator` | Statistical calculator for mean, median, variance, standard deviation, sum, min, max |
+| `PercentileCalculator` | Percentile computation with configurable interpolation strategies |
+
+**Calculator Example:**
+
+```java
+var stats = new Calculator(Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0));
+double mean = stats.getMean();
+double median = stats.getMedian();
+double stdDev = stats.getStandardDeviation();
+```
+
+**PercentileCalculator Example:**
+
+```java
+var calculator = new PercentileCalculator(data);
+double p95 = calculator.calculate(95);
+double p99 = calculator.calculate(99);
+```
+
+### Model
+
+| Class | Description |
+|-------------------|----------------------------------------------------------------|
+| `QuartileBounds` | Holds Q1, median (Q2), Q3 values along with IQR and whisker bounds |
+
+---
+
+## Tuple
+
+Lightweight generic tuple types for when you need to return multiple values without defining a dedicated class.
+
+### Classes
+
+| Class | Type Parameters | Mutability |
+|--------------------|-----------------|------------|
+| `Tuple` | Two elements | Mutable |
+| `ImmutableTuple` | Two elements | Immutable |
+| `Triple` | Three elements | Mutable |
+| `ImmutableTriple` | Three elements | Immutable |
+
+**Example:**
+
+```java
+var pair = Tuple.of("key", 42);
+var triple = Triple.of("id", "name", 100);
+var immutable = ImmutableTuple.of("constant", true);
+
+// Accessors
+String first = pair.getFirst();
+Integer second = pair.getSecond();
+
+// Triple accessors
+String a = triple.getFirst();
+String b = triple.getSecond();
+Integer c = triple.getThird();
+```
+
+---
+
+## Identity Generator
+
+Generates unique identifiers suitable for use as database primary keys or distributed IDs.
+
+### Interface
+
+`IdentityGenerator` — Generates identities of type `T`.
+
+### Implementations
+
+| Class | Description |
+|------------------------------|-----------------------------------------------------------------|
+| `SequentialUuidGenerator` | Generates time-ordered, sequential UUIDs (optimised for DB indexes) |
+| `SnowflakeIdentityGenerator` | Snowflake-style distributed unique ID generation |
+
+**Sequential UUID:**
+
+```java
+var generator = new SequentialUuidGenerator();
+UUID id = generator.nextId(); // time-ordered UUID, B-tree friendly
+```
+
+**Snowflake:**
+
+```java
+var generator = new SnowflakeIdentityGenerator(workerId, datacenterId);
+long id = generator.nextId(); // 64-bit snowflake ID
+```
+
+### Exceptions
+
+| Class | Description |
+|-------------------|----------------------------------------------------------------|
+| `TimingException` | Thrown when the system clock moves backwards, compromising ID uniqueness |
diff --git a/docs/en-gb/projects/onixbyte-toolbox/index.mdx b/docs/en-gb/projects/onixbyte-toolbox/index.mdx
new file mode 100644
index 0000000..b392ea8
--- /dev/null
+++ b/docs/en-gb/projects/onixbyte-toolbox/index.mdx
@@ -0,0 +1,54 @@
+---
+title: OnixByte Toolbox
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## Introduction
+
+OnixByte Toolbox is a Development Kit for Java applications that provides a set of convenient, reusable tools for writing code efficiently. It is designed and maintained by OnixByte as a monorepo containing multiple purpose-built libraries, each addressing a specific development need — from common utilities and cryptography to mathematical computation and identity generation.
+
+The toolkit is available on Maven Central under the `com.onixbyte` group ID. Each module is independently versioned and can be included in any Java 17+ project.
+
+## Modules
+
+| Module | Artifact ID | Description |
+|--------------------|----------------------|---------------------------------------------------------------------------|
+| Common Toolbox | `common-toolbox` | Everyday utilities — AES, hashing, Base64, collections, branching, ranges |
+| Crypto Toolbox | `crypto-toolbox` | Public/private key loading for RSA and ECDSA algorithms |
+| Math Toolbox | `math-toolbox` | Statistical calculation, percentile analysis, quartile computation |
+| Tuple | `tuple` | Generic 2-tuple and 3-tuple with immutable variants |
+| Identity Generator | `identity-generator` | Snowflake-style and sequential UUID identity generation |
+| Version Catalogue | `version-catalogue` | Centralised Gradle version catalogue for OnixByte projects |
+
+## Installation
+
+Add the desired module as a dependency in your build config:
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:$artefactId:$version")
+ }
+ ```
+
+
+
+ ```xml title="pom.xml"
+
+ com.onixbyte
+ ${artefactId}
+ ${version}
+
+ ```
+
+
+
+## Requirements
+
+- Java 17 or later
+
+## License
+
+OnixByte Toolbox is open-source software released under the MIT Licence.
diff --git a/docs/en-gb/projects/regions4j/index.mdx b/docs/en-gb/projects/regions4j/index.mdx
new file mode 100644
index 0000000..340b511
--- /dev/null
+++ b/docs/en-gb/projects/regions4j/index.mdx
@@ -0,0 +1,98 @@
+---
+title: Regions for Java
+---
+
+## Introduction
+
+**regions4j** is a lightweight, type-safe Java library that provides comprehensive metadata for world regions based on the ISO 3166-1 standard. It is designed to simplify internationalisation (i18n), telecommunication routing, and regional data management in Java-based enterprise applications.
+
+The library models every ISO 3166-1 country and territory as an enum constant, giving you compile-time safety and IDE autocompletion when referencing regions. With built-in O(1) lookups, zero external dependencies, and Java 8 compatibility, it is suitable for projects of any size — from microservices to monolithic enterprise systems.
+
+## Features
+
+- **ISO 3166-1 Compliant** — Full support for Alpha-2 (`abbreviation`) and Alpha-3 (`code`) formats across all assigned countries and territories.
+- **Telecommunication Metadata** — Includes E.164 international dialling prefixes for every region.
+- **Locality Support** — Default locale tags (`zh_HK`, `en_US`, `en_GB`, etc.) for each region to assist with i18n workflows.
+- **High Performance** — Thread-safe, immutable internal hash maps provide constant-time lookups by abbreviation or code.
+- **Zero Dependencies** — A pure Java library with no external overhead.
+- **Calendar Versioning** — Versions follow a `YYYY.MM` scheme (e.g. `2025.12`) to transparently indicate the freshness of the underlying ISO data, rather than semantic versioning.
+
+## Core Schema
+
+Each region exposes four attributes:
+
+| Attribute | Type | Description | Example |
+|----------------|--------|---------------------------------|------------------------------------|
+| `abbreviation` | String | ISO 3166-1 alpha-2 abbreviation | `HK`, `US`, `GB`, `RU` |
+| `code` | String | ISO 3166-1 alpha-3 code | `HKG`, `USA`, `GBR`, `RUS` |
+| `callingCode` | String | E.164 international dialling prefix | `852`, `1`, `44`, `7` |
+| `locale` | String | Default language and region tag | `zh_HK`, `en_US`, `en_GB`, `ru_RU` |
+
+## Installation
+
+**Maven:**
+
+```xml
+
+ com.onixbyte
+ regions4j
+ 2025.12
+
+```
+
+**Gradle (Kotlin DSL):**
+
+```kotlin
+implementation("com.onixbyte:regions4j:2025.12")
+```
+
+> **Versioning note:** This library uses Calendar Versioning (`YYYY.MM`) rather than Semantic Versioning. A version string like `2025.12` tells you immediately that the regional data reflects the ISO 3166-1 state as of December 2025.
+
+## Usage
+
+### Direct Access
+
+Reference any region directly via its enum constant:
+
+```java
+Region uk = Region.UNITED_KINGDOM;
+
+uk.getAbbreviation(); // "GB"
+uk.getCode(); // "GBR"
+uk.getDialCode(); // "44"
+uk.getLocale(); // "en_GB"
+```
+
+### Efficient Lookups
+
+Look up regions from string inputs — ideal for processing web requests, API payloads, or database records:
+
+```java
+// By Alpha-2 abbreviation (case-sensitive)
+Region region = Region.fromAbbreviation("HK");
+
+// By Alpha-3 code (case-insensitive)
+Region region = Region.fromCode("HKG");
+```
+
+### Java Locale Integration
+
+Convert a region's locale string to a `java.util.Locale` for use with standard Java i18n APIs:
+
+```java
+Region region = Region.CHINA;
+Locale javaLocale = Locale.forLanguageTag(region.getLocale().replace("_", "-"));
+javaLocale.getDisplayCountry(Locale.UK); // "China"
+```
+
+## Performance
+
+On first access, the library initialises all regions into immutable `HashMap` structures. Subsequent lookups via `fromAbbreviation()` and `fromCode()` are thread-safe and run in constant time — suitable for high-throughput request paths.
+
+## Requirements
+
+- Java 8 or later
+
+## License
+
+regions4j is open-source software released under the MIT License.
diff --git a/docs/en-gb/projects/vite-plugins/index.mdx b/docs/en-gb/projects/vite-plugins/index.mdx
new file mode 100644
index 0000000..88e44ed
--- /dev/null
+++ b/docs/en-gb/projects/vite-plugins/index.mdx
@@ -0,0 +1,11 @@
+---
+title: Vite Plugins
+---
+
+## Overview
+
+A collection of Vite plugins developed and maintained by OnixByte. Each plugin is designed to solve a specific problem in the Vite development workflow — lightweight, zero-dependency, and plug-and-play.
+
+## Available Plugins
+
+- **[Port Checker](/projects/vite-plugins/port-checker)** — Warns when the dev server listens on a browser-restricted port (per the Fetch specification), helping you avoid silent connection failures.
diff --git a/docs/en-gb/projects/vite-plugins/port-checker/index.mdx b/docs/en-gb/projects/vite-plugins/port-checker/index.mdx
new file mode 100644
index 0000000..7327d2d
--- /dev/null
+++ b/docs/en-gb/projects/vite-plugins/port-checker/index.mdx
@@ -0,0 +1,68 @@
+---
+title: Port Checker
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## Introduction
+
+**vite-plugin-port-checker** is a lightweight Vite plugin that warns you when the dev server is listening on a port blocked by common browsers. Browsers such as Chrome and Firefox maintain a [list of restricted ports](https://fetch.spec.whatwg.org/#port-blocking) — typically those associated with well-known protocols like SMTP, SSH, and DNS — and refuse to connect to them. Accidentally running your dev server on one of these ports leads to a confusing "connection refused" or "blocked" error with no clear explanation.
+
+This plugin detects the situation at startup and prints a clear, colour-coded warning to the console, advising you to change the `server.port` setting in your Vite configuration.
+
+## Features
+
+- **Automatic Detection** — Checks the dev server port against the complete Fetch spec port-blocking list (68 restricted ports).
+- **Clear Warnings** — Yellow-highlighted console output with actionable guidance.
+- **Zero Configuration** — Works out of the box with no options to set.
+- **Lightweight** — Single-file plugin with no dependencies beyond Vite itself.
+
+## Installation
+
+
+
+ ```bash
+ npm install vite-plugin-port-checker -D
+ ```
+
+
+ ```bash
+ pnpm add vite-plugin-port-checker -D
+ ```
+
+
+
+## Usage
+
+Add the plugin to your `vite.config.ts`:
+
+```ts
+// vite.config.ts
+import { defineConfig } from "vite"
+import checkRestrictedPort from "vite-plugin-port-checker"
+
+export default defineConfig({
+ plugins: [checkRestrictedPort()],
+})
+```
+
+When the dev server starts on a restricted port (e.g. port 25, 22, or 53), you will see:
+
+```
+[Warning] The current listening port 25 is categorised as a restricted port
+by most browsers. This may prevent you from accessing the application.
+Please consider changing the port in your 'vite.config.ts' or 'vite.config.js'
+via 'server.port'.
+```
+
+## How It Works
+
+The plugin hooks into Vite's `configureServer` lifecycle. Once the HTTP server emits the `listening` event, the plugin inspects the bound port and checks it against the hardcoded set of 68 restricted ports defined in the [Fetch specification](https://fetch.spec.whatwg.org/#port-blocking). If there is a match, a yellow `console.warn` message alerts the developer.
+
+## Requirements
+
+- Vite 3.0.0 or later
+
+## License
+
+vite-plugin-port-checker is open-source software released under the MIT License.
diff --git a/docs/zh-hans/_nav.json b/docs/zh-hans/_nav.json
index 64b7c36..c810b93 100644
--- a/docs/zh-hans/_nav.json
+++ b/docs/zh-hans/_nav.json
@@ -1,14 +1,14 @@
[
- {
- "text": "blogs",
- "link": "/blogs/",
- "activeMatch": "/blogs/"
- },
{
"text": "projects",
"link": "/projects/",
"activeMatch": "/projects/"
},
+ {
+ "text": "blogs",
+ "link": "/blogs/",
+ "activeMatch": "/blogs/"
+ },
{
"text": "notifications",
"link": "/notifications/",
diff --git a/docs/zh-hans/index.md b/docs/zh-hans/index.md
index 56f11e7..5c4183a 100644
--- a/docs/zh-hans/index.md
+++ b/docs/zh-hans/index.md
@@ -8,9 +8,6 @@ hero:
- theme: brand
text: 探索项目
link: https://github.com/onixbyte
- - theme: alt
- text: 体验 Dev Lab
- link: https://dev-lab.onixbyte.dev
features:
- title: OnixByte Toolbox
details: 一个多功能 Java 类库,为现代 Java 开发提供通用工具,无缝集成 Spring 生态。已上架 Maven Central。
diff --git a/docs/zh-hans/projects/calendar-toolbox/api.md b/docs/zh-hans/projects/calendar-toolbox/api.md
new file mode 100644
index 0000000..76184d0
--- /dev/null
+++ b/docs/zh-hans/projects/calendar-toolbox/api.md
@@ -0,0 +1,390 @@
+---
+title: Calendar Toolbox API
+---
+
+## 包结构概览
+
+库的代码组织在基础包 `com.onixbyte.calendar` 下,结构如下:
+
+| 包 | 描述 |
+|---|---|
+| `com.onixbyte.calendar` | 根日历对象 |
+| `com.onixbyte.calendar.component` | iCalendar 组件(VEVENT、VTODO 等) |
+| `com.onixbyte.calendar.component.property` | 组件级属性 |
+| `com.onixbyte.calendar.property` | 日历级属性 |
+| `com.onixbyte.calendar.parameter` | iCalendar 属性参数 |
+| `com.onixbyte.calendar.recurrence` | 重复规则类型 |
+| `com.onixbyte.calendar.value` | 值类型 |
+| `com.onixbyte.calendar.util` | 格式化工具类 |
+
+---
+
+## Calendar
+
+表示 iCalendar(RFC 5545)VCALENDAR 容器的顶层对象。
+
+```java
+Calendar calendar = Calendar.builder()
+ .withCalendarScale(...)
+ .withMethod(...)
+ .withProductIdentifier(...)
+ .withVersion(...)
+ .withOwner(...)
+ .withPrimaryCalendar(...)
+ .withPublishedTTL(...)
+ .withCalendarDescription(...)
+ .withCalendarName(...)
+ .withCalendarId(...)
+ .withCustomProperties(...)
+ .withComponents(event, todo, ...)
+ .build();
+
+String icsContent = calendar.formatted();
+```
+
+### 日历属性
+
+所有日历级属性位于 `com.onixbyte.calendar.property`,实现 `CalendarProperty` 接口。
+
+| 类 | iCalendar 属性 | 描述 |
+|---|---|---|
+| `CalendarScale` | `CALSCALE` | 日历系统(例如 GREGORIAN) |
+| `Method` | `METHOD` | iCalendar 方法(例如 PUBLISH、REQUEST) |
+| `ProductIdentifier` | `PRODID` | 日历的产品标识符 |
+| `Version` | `VERSION` | iCalendar 版本(例如 2.0) |
+| `Owner` | `X-OWNER` | 日历所有者 |
+| `PrimaryCalendar` | `X-PRIMARY-CALENDAR` | 是否为主日历 |
+| `PublishedTTL` | `X-PUBLISHED-TTL` | 已发布日历的生存时间 |
+| `CalendarDescription` | `X-CALENDAR-DESC` | 日历描述 |
+| `CalendarName` | `X-CALENDAR-NAME` | 日历名称 |
+| `CalendarId` | `X-CALENDAR-ID` | 日历标识符 |
+| `CustomCalendarProperty` | `X-*` | 自定义日历属性 |
+
+自定义属性使用 Builder 创建:
+
+```java
+var customProp = CustomCalendarProperty.builder()
+ .withParameters(...)
+ .build("X-MY-PROPERTY", "my-value");
+```
+
+> 注意:自定义属性名称**必须**以 `X-` 开头。
+
+---
+
+## 组件
+
+组件是 iCalendar 对象的核心实体。每个组件实现 `CalendarComponent` 接口,并在 `BEGIN:TYPE` 和 `END:TYPE` 定界符之间渲染。
+
+### Event(VEVENT)
+
+表示一个预定的活动/事件。
+
+```java
+Event event = Event.builder()
+ .withDateTimeStamp(dtstamp) // 必需
+ .withUniqueIdentifier(uid) // 必需
+ .withDateTimeStart(dtstart)
+ .withDateTimeEnd(dtend) // 与 duration 互斥
+ .withDuration(duration) // 与 dtend 互斥
+ .withSummary(summary)
+ .withDescription(description)
+ .withClassification(classification)
+ .withDateTimeCreated(dateTimeCreated)
+ .withGeographicPosition(geoPos)
+ .withLastModified(lastModified)
+ .withLocation(location)
+ .withOrganiser(organiser)
+ .withPriority(priority)
+ .withSequenceNumber(seqNumber)
+ .withStatus(status)
+ .withTimeTransparency(transparency)
+ .withUniformResourceLocator(url)
+ .withRecurrenceId(recurrenceId)
+ .withRecurrenceRule(rrule)
+ .withAttachments(attachments)
+ .withAttendees(attendees)
+ .withCategories(categories)
+ .withComments(comments)
+ .withContacts(contacts)
+ .withExceptionDateTimes(exDates)
+ .withRequestStatuses(statuses)
+ .withRelated(related)
+ .withResources(resources)
+ .withRecurrenceDateTimes(rDates)
+ .build();
+```
+
+### Todo(VTODO)
+
+表示待办事项或任务。
+
+```java
+Todo todo = Todo.builder()
+ .withDateTimeStamp(dtstamp) // 必需
+ .withUniqueIdentifier(uid) // 必需
+ .withSummary(summary)
+ .withDateTimeStart(dtstart)
+ .withDateTimeDue(due) // 与 duration 互斥
+ .withDuration(duration) // 与 due 互斥
+ .withDateTimeCompleted(completed)
+ .withPercentComplete(percent)
+ .withClassification(classification)
+ .withDateTimeCreated(created)
+ .withDescription(description)
+ .withGeographicPosition(geoPos)
+ .withLastModified(lastModified)
+ .withLocation(location)
+ .withOrganiser(organiser)
+ .withPriority(priority)
+ .withSequenceNumber(seq)
+ .withStatus(status)
+ .withRecurrenceId(recurId)
+ .withRecurrenceRule(rrule)
+ .withUniformResourceLocator(url)
+ .withAttachments(attachments)
+ .withAttendees(attendees)
+ .withCategories(categories)
+ .withComments(comments)
+ .withContacts(contacts)
+ .withExceptionDateTimes(exDates)
+ .withRequestStatuses(statuses)
+ .withRelatedToList(related)
+ .withResources(resources)
+ .withRecurrenceDateTimes(rDates)
+ .build();
+```
+
+### Journal(VJOURNAL)
+
+表示日记条目或笔记。
+
+```java
+Journal journal = Journal.builder()
+ .withDateTimeStamp(dtstamp) // 必需
+ .withUniqueIdentifier(uid) // 必需
+ .withSummary(summary)
+ .withClassification(classification)
+ .withDateTimeCreated(created)
+ .withDateTimeStart(dtstart)
+ .withLastModified(lastModified)
+ .withOrganiser(organiser)
+ .withRecurrenceId(recurId)
+ .withSequenceNumber(seq)
+ .withStatus(status)
+ .withUniformResourceLocator(url)
+ .withRecurrenceRule(rrule)
+ .withAttachments(attachments)
+ .withAttendees(attendees)
+ .withCategories(categories)
+ .withComments(comments)
+ .withContacts(contacts)
+ .withDescriptions(descriptions)
+ .withExceptionDateTimes(exDates)
+ .withRelatedToList(related)
+ .withRecurrenceDate(rDates)
+ .withRequestStatuses(statuses)
+ .build();
+```
+
+### FreeBusy(VFREEBUSY)
+
+表示空闲/忙碌时间信息。
+
+```java
+FreeBusy freeBusy = FreeBusy.builder()
+ .withDateTimeStamp(dtstamp) // 必需
+ .withUniqueIdentifier(uid) // 必需
+ .withContact(contact)
+ .withDateTimeStart(dtstart)
+ .withDateTimeEnd(dtend)
+ .withOrganiser(organiser)
+ .withUniformResourceLocator(url)
+ .withAttendees(attendees)
+ .withComments(comments)
+ .withFreeBusyTimes(freeBusyTimes)
+ .withRequestStatuses(statuses)
+ .build();
+```
+
+### TimeZone(VTIMEZONE)
+
+定义时区规则,包括标准时间和夏令时转换。
+
+```java
+TimeZone timezone = TimeZone.builder()
+ .withTimeZoneIdentifier(tzId)
+ .withLastModified(lastModified)
+ .withTimeZoneUrl(tzUrl)
+ .withTimeZoneProperties(standardProp, daylightProp)
+ .build();
+```
+
+时区属性定义实际的转换规则:
+
+```java
+TimeZoneProperty standard = TimeZoneProperty.builder()
+ .withDateTimeStart(dtstart)
+ .withTimeZoneOffsetTo(offsetTo)
+ .withTimeZoneOffsetFrom(offsetFrom)
+ .withRecurrenceRule(rrule)
+ .withTimeZoneNames(tzName)
+ .buildStandard(); // 或 buildDaylight()
+
+TimeZoneProperty daylight = TimeZoneProperty.builder()
+ .withDateTimeStart(dtstart)
+ .withTimeZoneOffsetTo(offsetTo)
+ .withTimeZoneOffsetFrom(offsetFrom)
+ .buildDaylight();
+```
+
+### Alarm(VALARM)
+
+定义闹钟/提醒通知。支持三种闹钟类型:
+
+```java
+// 音频闹钟
+Alarm audioAlarm = Alarm.builder()
+ .withTrigger(trigger)
+ .withDuration(duration)
+ .withRepeatCount(repeatCount)
+ .withAttachments(audioAttachment)
+ .buildAudio();
+
+// 显示闹钟
+Alarm displayAlarm = Alarm.builder()
+ .withTrigger(trigger)
+ .withDescription(description) // 必需
+ .withDuration(duration)
+ .withRepeatCount(repeatCount)
+ .buildDisplay();
+
+// 邮件闹钟
+Alarm emailAlarm = Alarm.builder()
+ .withTrigger(trigger)
+ .withDescription(description) // 必需
+ .withSummary(summary) // 必需
+ .withAttendees(attendees) // 必需
+ .withDuration(duration)
+ .withRepeatCount(repeatCount)
+ .buildEmail();
+```
+
+---
+
+## 组件属性
+
+组件属性位于 `com.onixbyte.calendar.component.property`,实现 `ComponentProperty` 接口。
+
+| 类 | iCalendar 属性 | 描述 |
+|---|---|---|
+| `Action` | `ACTION` | 闹钟操作类型(AUDIO、DISPLAY、EMAIL) |
+| `Attachment` | `ATTACH` | 文档附件 |
+| `Attendee` | `ATTENDEE` | 事件/任务参与者 |
+| `Categories` | `CATEGORIES` | 类别或标签 |
+| `Classification` | `CLASS` | 访问分类(PUBLIC、PRIVATE、CONFIDENTIAL) |
+| `Comment` | `COMMENT` | 评论 |
+| `Contact` | `CONTACT` | 联系信息 |
+| `DateTimeCompleted` | `COMPLETED` | 完成日期时间 |
+| `DateTimeCreated` | `CREATED` | 创建日期时间 |
+| `DateTimeDue` | `DUE` | 截止日期时间 |
+| `DateTimeEnd` | `DTEND` | 结束日期时间 |
+| `DateTimeStamp` | `DTSTAMP` | 日期时间戳 |
+| `DateTimeStart` | `DTSTART` | 开始日期时间 |
+| `Description` | `DESCRIPTION` | 描述 |
+| `ExceptionDateTimes` | `EXDATE` | 例外日期时间 |
+| `FreeBusyTime` | `FREEBUSY` | 空闲/忙碌时间段 |
+| `GeographicPosition` | `GEO` | 地理位置(纬度/经度) |
+| `LastModified` | `LAST-MODIFIED` | 最后修改日期时间 |
+| `Location` | `LOCATION` | 地点 |
+| `Organiser` | `ORGANIZER` | 组织者 |
+| `PercentComplete` | `PERCENT-COMPLETE` | 完成百分比 |
+| `Priority` | `PRIORITY` | 优先级 |
+| `RecurrenceDateTimes` | `RDATE` | 重复日期时间 |
+| `RecurrenceId` | `RECURRENCE-ID` | 重复实例标识符 |
+| `RecurrenceRule` | `RRULE` | 重复规则 |
+| `RelatedTo` | `RELATED-TO` | 相关组件引用 |
+| `RepeatCount` | `REPEAT` | 闹钟重复次数 |
+| `RequestStatus` | `REQUEST-STATUS` | 请求状态 |
+| `Resources` | `RESOURCES` | 资源 |
+| `SequenceNumber` | `SEQUENCE` | 序列号(修订版本) |
+| `Status` | `STATUS` | 组件状态(TENTATIVE、CONFIRMED、CANCELLED 等) |
+| `Summary` | `SUMMARY` | 标题或摘要 |
+| `TimeTransparency` | `TRANSP` | 时间透明度(OPAQUE、TRANSPARENT) |
+| `TimeZoneIdentifier` | `TZID` | 时区标识符 |
+| `TimeZoneName` | `TZNAME` | 时区名称 |
+| `TimeZoneOffsetFrom` | `TZOFFSETFROM` | 相对于 UTC 的时区偏移(原) |
+| `TimeZoneOffsetTo` | `TZOFFSETTO` | 相对于 UTC 的时区偏移(目标) |
+| `TimeZoneUrl` | `TZURL` | 时区 URL |
+| `Trigger` | `TRIGGER` | 闹钟触发器 |
+| `UniformResourceLocator` | `URL` | 关联 URL |
+| `UniqueIdentifier` | `UID` | 唯一标识符 |
+| `CustomComponentProperty` | `X-*` | 自定义组件属性 |
+
+---
+
+## 参数
+
+参数位于 `com.onixbyte.calendar.parameter`,为组件属性提供额外限定。
+
+| 类 | iCalendar 参数 | 描述 |
+|---|---|---|
+| `AlarmTriggerRelationship` | `RELATED` | 触发器关联(START、END) |
+| `AlternateTextRepresentation` | `ALTREP` | 替代文本 URI |
+| `CalendarUserType` | `CUTYPE` | 日历用户类型(INDIVIDUAL、GROUP、RESOURCE 等) |
+| `CommonName` | `CN` | 通用名称 |
+| `Delegatees` | `DELEGATED-TO` | 受托人 |
+| `Delegators` | `DELEGATED-FROM` | 委托人 |
+| `DirectoryEntryReference` | `DIR` | 目录条目 URI |
+| `FormatType` | `FMTTYPE` | 格式类型(MIME 类型) |
+| `FreeBusyTimeType` | `FBTYPE` | 空闲/忙碌时间类型 |
+| `InlineEncoding` | `ENCODING` | 内联编码(BASE64) |
+| `Language` | `LANGUAGE` | 语言 |
+| `Membership` | `MEMBER` | 组成员 |
+| `ParticipationRole` | `ROLE` | 参与角色(CHAIR、REQ-PARTICIPANT 等) |
+| `ParticipationStatus` | `PARTSTAT` | 参与状态(ACCEPTED、DECLINED 等) |
+| `RecurrenceIdentifierRange` | `RANGE` | 重复范围(THISANDPRIOR、THISANDFUTURE) |
+| `RelationshipType` | `RELTYPE` | 关系类型(PARENT、CHILD、SIBLING) |
+| `RsvpExpectation` | `RSVP` | RSVP 期望(TRUE、FALSE) |
+| `SentBy` | `SENT-BY` | 发送者 |
+| `TimeZoneIdentifier` | `TZID` | 时区标识符 |
+| `ValueDataType` | `VALUE` | 值数据类型(DATE、DATE-TIME 等) |
+
+---
+
+## 递归类型
+
+位于 `com.onixbyte.calendar.recurrence`。
+
+| 类 | 描述 |
+|---|---|
+| `Frequency` | 重复频率常量(DAILY、WEEKLY、MONTHLY、YEARLY),用于重复规则 |
+| `WeekdayNum` | 重复规则的星期序号(例如第 2 个星期一) |
+
+---
+
+## 值类型
+
+位于 `com.onixbyte.calendar.value`。
+
+| 类 | 描述 |
+|---|---|
+| `FreeBusyTimeValue` | 表示空闲/忙碌时间值 |
+| `PeriodOfTime` | 表示一个时间段,包含开始和结束 |
+| `PropertyValue` | 属性的基础值类型 |
+| `UtcOffset` | UTC 偏移值(例如 `-05:00`、`+01:00`) |
+
+---
+
+## 格式化输出
+
+所有组件和属性都提供 `formatted()` 方法,返回符合 iCalendar 规范的字符串。`Calendar.formatted()` 方法生成完整的 `.ics` 输出,包含 `BEGIN:VCALENDAR`/`END:VCALENDAR`。
+
+```java
+String ics = calendar.formatted();
+// BEGIN:VCALENDAR
+// CALSCALE:GREGORIAN
+// METHOD:PUBLISH
+// ...
+// END:VCALENDAR
+```
diff --git a/docs/zh-hans/projects/calendar-toolbox/index.mdx b/docs/zh-hans/projects/calendar-toolbox/index.mdx
new file mode 100644
index 0000000..fb7f995
--- /dev/null
+++ b/docs/zh-hans/projects/calendar-toolbox/index.mdx
@@ -0,0 +1,102 @@
+---
+title: Calendar Toolbox
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## 介绍
+
+Calendar Toolbox 是一个 Java 库,旨在简化遵循 iCalendar 规范(RFC 5545)的 `.ics` 文件的创建。该库为开发者提供了简洁的 API,可生成能够导入到 Microsoft Outlook、Google Calendar 和 Apple Calendar 等主流日历应用程序中的日历事件。
+
+通过 Calendar Toolbox,您可以以编程方式轻松创建、定制和导出日历事件文件,从而以最少的代价将日历功能集成到您的 Java 应用中。
+
+## 特性
+
+- **完整 RFC 5545 兼容** — 支持 VEVENT、VTODO、VJOURNAL、VFREEBUSY、VTIMEZONE 和 VALARM 等标准 iCalendar 组件。
+- **流式 Builder 模式** — 所有组件和属性均使用 Builder 模式,构建过程可读性强且直观。
+- **类型安全属性** — 强类型的属性和参数确保编译期正确性。
+- **自定义扩展** — 支持日历级和组件级的自定义 `X-` 属性。
+- **轻量级** — 核心功能零外部依赖。
+
+## 安装
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:calendar-toolbox:1.1.0")
+ }
+ ```
+
+
+ ```xml title="pom.xml"
+
+
+ com.onixbyte
+ calendar-toolbox
+ 1.1.0
+
+
+ ```
+
+
+
+## 快速开始
+
+```java
+import com.onixbyte.calendar.Calendar;
+import com.onixbyte.calendar.component.Event;
+import com.onixbyte.calendar.component.property.*;
+import com.onixbyte.calendar.property.*;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+public class CalendarExample {
+
+ public static void main(String[] args) {
+ // 创建所需的日期时间属性
+ var now = ZonedDateTime.now(ZoneOffset.UTC);
+ var dtstamp = DateTimeStamp.of(now);
+ var uid = UniqueIdentifier.of("meeting-001@example.com");
+ var dtstart = DateTimeStart.of(
+ LocalDateTime.of(2025, 8, 15, 9, 0),
+ "America/New_York"
+ );
+ var dtend = DateTimeEnd.of(
+ LocalDateTime.of(2025, 8, 15, 10, 0),
+ "America/New_York"
+ );
+ var summary = Summary.of("Team Standup");
+ var description = Description.of("Daily team standup meeting.");
+
+ // 构建事件
+ var event = Event.builder()
+ .withDateTimeStamp(dtstamp)
+ .withUniqueIdentifier(uid)
+ .withDateTimeStart(dtstart)
+ .withDateTimeEnd(dtend)
+ .withSummary(summary)
+ .withDescription(description)
+ .build();
+
+ // 构建日历并输出 .ics 内容
+ var calendar = Calendar.builder()
+ .withCalendarScale(CalendarScale.of("GREGORIAN"))
+ .withMethod(Method.of("PUBLISH"))
+ .withProductIdentifier(ProductIdentifier.of("-//OnixByte//Calendar Toolbox//EN"))
+ .withVersion(Version.of("2.0"))
+ .withComponents(event)
+ .build();
+
+ System.out.println(calendar.formatted());
+ }
+}
+```
+
+上述代码会生成一个 `.ics` 格式的字符串,可以保存为文件或通过邮件发送。
+
+## 许可证
+
+Calendar Toolbox 是采用 MIT 许可证发布的开源软件。
diff --git a/docs/zh-hans/projects/captcha/api.md b/docs/zh-hans/projects/captcha/api.md
new file mode 100644
index 0000000..60370ad
--- /dev/null
+++ b/docs/zh-hans/projects/captcha/api.md
@@ -0,0 +1,248 @@
+---
+title: Captcha API
+---
+
+## 包结构概览
+
+库的代码组织在基础包 `com.onixbyte.captcha` 下,结构如下:
+
+| 包 | 描述 |
+|---|---|
+| `com.onixbyte.captcha` | 核心接口 |
+| `com.onixbyte.captcha.impl` | 默认实现 |
+| `com.onixbyte.captcha.text` | 文本生成器和渲染器接口 |
+| `com.onixbyte.captcha.text.impl` | 文本生成器和渲染器实现 |
+| `com.onixbyte.captcha.text.enums` | 文本相关枚举 |
+| `com.onixbyte.captcha.background` | 背景生成器接口 |
+| `com.onixbyte.captcha.background.impl` | 背景生成器实现 |
+| `com.onixbyte.captcha.noise` | 噪点生成器接口 |
+| `com.onixbyte.captcha.noise.impl` | 噪点生成器实现 |
+| `com.onixbyte.captcha.gimpy` | 扭曲引擎接口 |
+| `com.onixbyte.captcha.gimpy.impl` | 扭曲引擎实现 |
+
+---
+
+## Producer
+
+负责创建 CAPTCHA 图片并在其上绘制文字的顶层接口。
+
+```java
+Producer captcha = DefaultCaptchaProducer.builder()
+ .textProducer(textProducer)
+ .wordRenderer(wordRenderer)
+ .gimpyEngine(gimpyEngine)
+ .backgroundProducer(backgroundProducer)
+ .width(200)
+ .height(50)
+ .borderDrawn(true)
+ .borderColour(Color.BLACK)
+ .borderThickness(1)
+ .build();
+
+String text = captcha.createText();
+BufferedImage image = captcha.createImage(text);
+```
+
+### DefaultCaptchaProducer Builder
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `textProducer` | `DefaultTextProducer.builder().build()` | 文本生成器 |
+| `wordRenderer` | `DefaultWordRenderer.builder().build()` | 文字渲染器 |
+| `gimpyEngine` | `WaterRipple.builder().build()` | 扭曲引擎 |
+| `backgroundProducer` | `DefaultBackgroundProducer.builder().build()` | 背景生成器 |
+| `width` | `200` | 验证码图片宽度 |
+| `height` | `50` | 验证码图片高度 |
+| `borderDrawn` | `true` | 是否绘制边框 |
+| `borderColour` | `Color.BLACK` | 边框颜色 |
+| `borderThickness` | `1` | 边框厚度 |
+
+---
+
+## Text
+
+### TextProducer
+
+用于创建 CAPTCHA 文本字符串的接口。
+
+```java
+public interface TextProducer {
+ String getText();
+}
+```
+
+#### DefaultTextProducer
+
+生成可配置长度和字符集的随机文本。
+
+```java
+DefaultTextProducer textProducer = DefaultTextProducer.builder()
+ .length(6) // 默认: 6
+ .chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) // 默认: a-z, A-Z, 0-9
+ .build();
+```
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `length` | `6` | 生成文本的长度 |
+| `chars` | `a-z`、`A-Z`、`0-9`(共 62 个字符) | 生成文本使用的字符集 |
+
+### WordRenderer
+
+将文字渲染到图片上的接口。
+
+```java
+public interface WordRenderer {
+ BufferedImage renderWord(String word, int width, int height);
+}
+```
+
+#### DefaultWordRenderer
+
+使用可配置的字体、颜色和间距渲染文字。
+
+```java
+DefaultWordRenderer wordRenderer = DefaultWordRenderer.builder()
+ .fontSize(40) // 默认: 40
+ .fonts("Arial", "Courier") // 默认: Arial, Courier
+ .fontColour(Color.BLACK) // 默认: Color.BLACK
+ .charSpace(2) // 默认: 2
+ .fontStyle(FontStyle.BOLD) // 默认: FontStyle.BOLD
+ .build();
+```
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `fontSize` | `40` | 字号(像素) |
+| `fonts` | `["Arial", "Courier"]` | 字体族(随机选择) |
+| `fontColour` | `Color.BLACK` | 字体颜色 |
+| `charSpace` | `2` | 字符间距(像素) |
+| `fontStyle` | `FontStyle.BOLD` | 字体样式 |
+
+### FontStyle
+
+定义 CAPTCHA 文字渲染支持的字体样式。
+
+| 值 | 对应的 AWT 常量 | 描述 |
+|---|---|---|
+| `PLAIN` | `java.awt.Font.PLAIN` | 普通样式 |
+| `BOLD` | `java.awt.Font.BOLD` | 粗体 |
+| `ITALIC` | `java.awt.Font.ITALIC` | 斜体 |
+| `BOLD_ITALIC` | `java.awt.Font.BOLD | Font.ITALIC` | 粗斜体 |
+
+---
+
+## GimpyEngine
+
+用于对图片应用扭曲效果的接口。
+
+```java
+public interface GimpyEngine {
+ BufferedImage getDistortedImage(BufferedImage baseImage);
+}
+```
+
+### WaterRipple
+
+应用水波纹扭曲效果。继承 `AbstractGimpyEngine`,自动添加噪点。
+
+```java
+WaterRipple gimpy = WaterRipple.builder()
+ .noiseProducer(DefaultNoiseProducer.builder().build()) // 默认: DefaultNoiseProducer
+ .build();
+```
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `noiseProducer` | `DefaultNoiseProducer.builder().build()` | 噪点生成器 |
+
+### FishEyeGimpy
+
+应用鱼眼扭曲效果,在图片上绘制水平和垂直线条。
+
+```java
+FishEyeGimpy gimpy = FishEyeGimpy.builder()
+ .build();
+```
+
+### ShadowGimpy
+
+应用阴影和波纹效果。继承 `AbstractGimpyEngine`,自动添加噪点。
+
+```java
+ShadowGimpy gimpy = ShadowGimpy.builder()
+ .noiseProducer(DefaultNoiseProducer.builder().build()) // 默认: DefaultNoiseProducer
+ .build();
+```
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `noiseProducer` | `DefaultNoiseProducer.builder().build()` | 噪点生成器 |
+
+---
+
+## Noise
+
+### NoiseProducer
+
+向图片添加噪点的接口。
+
+```java
+public interface NoiseProducer {
+ void makeNoise(BufferedImage image, float factorOne, float factorTwo,
+ float factorThree, float factorFour);
+}
+```
+
+#### DefaultNoiseProducer
+
+使用可配置的颜色添加噪点曲线。
+
+```java
+DefaultNoiseProducer noise = DefaultNoiseProducer.builder()
+ .noiseColour(Color.BLACK) // 默认: Color.BLACK
+ .build();
+```
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `noiseColour` | `Color.BLACK` | 噪点颜色 |
+
+#### NoNoiseProducer
+
+不向图片添加任何噪点的空实现。
+
+```java
+NoiseProducer noise = NoNoiseProducer.builder()
+ .build();
+```
+
+---
+
+## Background
+
+### BackgroundProducer
+
+向图片添加背景的接口。
+
+```java
+public interface BackgroundProducer {
+ BufferedImage addBackground(BufferedImage image);
+}
+```
+
+#### DefaultBackgroundProducer
+
+创建具有可配置起始和结束颜色的渐变背景。
+
+```java
+DefaultBackgroundProducer background = DefaultBackgroundProducer.builder()
+ .colourFrom(Color.WHITE) // 默认: Color.LIGHT_GRAY
+ .colourTo(Color.LIGHT_GRAY) // 默认: Color.WHITE
+ .build();
+```
+
+| 方法 | 默认值 | 描述 |
+|---|---|---|
+| `colourFrom` | `Color.LIGHT_GRAY` | 渐变起始颜色 |
+| `colourTo` | `Color.WHITE` | 渐变结束颜色 |
diff --git a/docs/zh-hans/projects/captcha/index.mdx b/docs/zh-hans/projects/captcha/index.mdx
new file mode 100644
index 0000000..68dd663
--- /dev/null
+++ b/docs/zh-hans/projects/captcha/index.mdx
@@ -0,0 +1,89 @@
+---
+title: Captcha
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## 介绍
+
+Captcha 是一个用于生成 CAPTCHA 验证码图片的 Java 库。本项目是 Google Kaptcha 的精神继承者,按照现代开发实践进行了现代化改造。
+
+通过 Captcha,您可以轻松生成可定制的 CAPTCHA 图片,支持多种扭曲效果、噪点和背景选项,轻松集成到您的 Java 应用中。
+
+## 特性
+
+- **易于集成** — 基于 Builder 的简洁 API,快速完成配置和集成。
+- **可定制的验证码生成** — 配置文本长度、字符集、字体样式和颜色。
+- **多种扭曲效果** — 支持水波纹、鱼眼和阴影效果。
+- **可配置噪点** — 使用自定义颜色添加噪点线条,或完全禁用噪点。
+- **渐变背景** — 可自定义的渐变背景颜色。
+- **简洁现代的代码** — 文档完善、类型安全且易于扩展。
+
+## 安装
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:captcha:1.0.0")
+ }
+ ```
+
+
+ ```xml title="pom.xml"
+
+
+ com.onixbyte
+ captcha
+ 1.0.0
+
+
+ ```
+
+
+
+## 快速开始
+
+```java
+import com.onixbyte.captcha.Producer;
+import com.onixbyte.captcha.background.BackgroundProducer;
+import com.onixbyte.captcha.background.impl.DefaultBackgroundProducer;
+import com.onixbyte.captcha.gimpy.GimpyEngine;
+import com.onixbyte.captcha.gimpy.impl.WaterRipple;
+import com.onixbyte.captcha.impl.DefaultCaptchaProducer;
+import com.onixbyte.captcha.noise.NoiseProducer;
+import com.onixbyte.captcha.noise.impl.DefaultNoiseProducer;
+import com.onixbyte.captcha.text.TextProducer;
+import com.onixbyte.captcha.text.WordRenderer;
+import com.onixbyte.captcha.text.impl.DefaultTextProducer;
+import com.onixbyte.captcha.text.impl.DefaultWordRenderer;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+public class CaptchaExample {
+
+ public static void main(String[] args) throws IOException {
+ // 使用默认配置创建 CAPTCHA 生产者
+ Producer captcha = DefaultCaptchaProducer.builder().build();
+
+ // 生成文本并创建图片
+ String captchaText = captcha.createText();
+ BufferedImage captchaImage = captcha.createImage(captchaText);
+
+ // 保存图片到文件
+ ImageIO.write(captchaImage, "png", new File("captcha.png"));
+
+ System.out.println("CAPTCHA 文本: " + captchaText);
+ }
+}
+```
+
+以上代码生成一张包含 6 位随机字符的 CAPTCHA 图片,并将其保存为 PNG 文件。
+
+## 许可证
+
+Captcha 是采用 MIT 许可证发布的开源软件。
diff --git a/docs/zh-hans/projects/delta-force-guide/api.md b/docs/zh-hans/projects/delta-force-guide/api.md
new file mode 100644
index 0000000..47ebe05
--- /dev/null
+++ b/docs/zh-hans/projects/delta-force-guide/api.md
@@ -0,0 +1,91 @@
+---
+title: Delta Force Guide API
+---
+
+## 后端 API 概览
+
+后端是基于 Spring Boot 3 的应用程序,代码组织在基础包 `com.onixbyte.deltaforceguide` 下:
+
+| 包 | 描述 |
+|---|---|
+| `controller` | REST API 端点控制器 |
+| `service` | 业务逻辑层 |
+| `repository` | MyBatis 数据访问层 |
+| `domain` | JPA 实体与领域对象 |
+| `config` | Spring 配置(安全、缓存等) |
+| `properties` | 配置属性类 |
+| `enumeration` | 枚举类型 |
+| `shared` | 共享工具类 |
+
+## API 端点
+
+### 认证
+
+| 方法 | 路径 | 描述 | 认证 |
+|---|---|---|---|
+| `POST` | `/api/auth/login` | 使用凭证登录 | 否 |
+| `POST` | `/api/auth/refresh` | 刷新 access token | 否 |
+| `GET` | `/api/auth/profile` | 获取当前用户信息 | 是 |
+
+### 枪械
+
+| 方法 | 路径 | 描述 |
+|---|---|---|
+| `GET` | `/api/firearms` | 枪械列表(分页,可按类型筛选) |
+| `GET` | `/api/firearms/:id` | 按 ID 获取枪械详情 |
+| `POST` | `/api/firearms` | 创建新枪械 |
+| `PUT` | `/api/firearms/:id` | 更新枪械信息 |
+| `DELETE` | `/api/firearms/:id` | 删除枪械 |
+
+### 改装
+
+| 方法 | 路径 | 描述 |
+|---|---|---|
+| `GET` | `/api/modifications` | 改装列表(分页,可按枪械和标签筛选) |
+| `GET` | `/api/modifications/:id` | 按 ID 获取改装详情 |
+| `POST` | `/api/modifications` | 创建改装 |
+| `POST` | `/api/modifications/batch` | 批量创建改装 |
+| `PUT` | `/api/modifications/:id` | 更新改装 |
+| `DELETE` | `/api/modifications/:id` | 删除改装 |
+| `DELETE` | `/api/modifications/batch-delete` | 批量删除改装 |
+
+### 标签
+
+| 方法 | 路径 | 描述 |
+|---|---|---|
+| `GET` | `/api/tags` | 获取所有标签 |
+
+## 前端路由
+
+| 路径 | 布局 | 页面 | 描述 |
+|---|---|---|---|
+| `/` | 主布局 | 枪械浏览 | 首页 — 枪械列表 |
+| `/firearms` | 主布局 | 枪械浏览 | 枪械详情与搜索 |
+| `/mod-codes` | 主布局 | 改装代码 | 改装代码库 |
+| `/legal` | 主布局 | 法律信息 | 法律与隐私信息 |
+| `/login` | 空白布局 | 登录 | 用户认证页面 |
+
+## 前端状态管理
+
+Redux Toolkit 结合 Redux Persist 管理以下状态:
+
+- **认证状态** — Access token、refresh token、用户信息
+- **设置状态** — 用户偏好,持久化至本地存储
+
+## API 客户端
+
+前端使用基于 Axios 封装的共享 `WebClient`,提供以下能力:
+
+- 基础 URL 配置(指向后端 API)
+- 通过请求拦截器自动注入 JWT access token
+- 在收到 401 响应时自动刷新 token
+
+## 基础设施
+
+| 组件 | 技术 |
+|---|---|
+| 数据库 | PostgreSQL(使用 Flyway 进行数据库迁移) |
+| 缓存 | Redis(会话和 token 存储) |
+| 文件存储 | AWS S3(枪械图片) |
+| 容器化 | Docker |
+| 部署 | Docker Compose + Nginx |
diff --git a/docs/zh-hans/projects/delta-force-guide/index.mdx b/docs/zh-hans/projects/delta-force-guide/index.mdx
new file mode 100644
index 0000000..26bd9c6
--- /dev/null
+++ b/docs/zh-hans/projects/delta-force-guide/index.mdx
@@ -0,0 +1,48 @@
+---
+title: Delta Force Guide
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## 介绍
+
+Delta Force Guide 是一个全栈 Web 应用,为游戏 Delta Force(三角洲部队)提供可搜索的枪械改装代码库。项目包含两个组件:
+
+- **Web 前端** — 基于 React 的单页应用,用于浏览、筛选和复制改装代码。
+- **后端服务** — 基于 Spring Boot 的 REST API,处理数据持久化、身份认证和内容管理。
+
+线上站点位于 **[dfguide.onixbyte.cn](https://dfguide.onixbyte.cn)**。
+
+## 特性
+
+- **枪械浏览** — 浏览精选的游戏内枪械列表及详细属性。
+- **改装代码库** — 按武器、模式和标签搜索筛选改装代码。
+- **一键复制** — 直接从界面复制改装代码。
+- **高效渲染** — 通过窗口虚拟化实现大列表的流畅渲染。
+- **身份认证** — 支持用户登录,采用 JWT 认证和验证码校验。
+- **后台管理** — 枪械与改装数据完整的增删改查功能。
+- **静态友好** — 前端以静态站点部署,通过 API 代理与后端通信。
+
+## 架构
+
+| 组件 | 技术栈 |
+|---|---|
+| **前端** | React 19、TypeScript、Tailwind CSS 4、Ant Design 6、React Router 7、Redux Toolkit、TanStack Virtual |
+| **后端** | Spring Boot 3、Java 21、PostgreSQL、MyBatis、Flyway、Redis |
+| **认证** | JWT(access 和 refresh token)、验证码集成 |
+| **存储** | AWS S3(图片上传) |
+
+前端是由 Vite 构建的静态站点,通过 API 与 Spring Boot 后端通信。认证采用 JWT access 和 refresh token 机制,refresh token 通过 Redis 管理。
+
+## 代码仓库
+
+- [delta-force-guide-server](https://github.com/onixbyte/delta-force-guide-server) — Spring Boot 后端
+- [delta-force-guide-web](https://github.com/onixbyte/delta-force-guide-web) — React 前端
+
+## 快速链接
+
+- **线上站点:** [dfguide.onixbyte.cn](https://dfguide.onixbyte.cn)
+
+## 许可证
+
+Delta Force Guide 是采用 MIT 许可证发布的开源软件。
diff --git a/docs/zh-hans/projects/helix/index.mdx b/docs/zh-hans/projects/helix/index.mdx
new file mode 100644
index 0000000..d8b2261
--- /dev/null
+++ b/docs/zh-hans/projects/helix/index.mdx
@@ -0,0 +1,71 @@
+---
+title: Helix
+---
+
+## 介绍
+
+Helix 是一个全栈企业级应用模板,旨在加速生产级业务应用的开发。它提供了预构建的基础,包含企业应用所需的全部基本功能,使团队能够专注于业务逻辑而非基础设施。
+
+项目由两个组件构成:
+
+- **Helix Server** — 基于 Spring Boot 的后端,提供 REST API、身份认证、权限管理和数据管理。
+- **Helix Web** — 基于 React 的单页应用前端,具备现代化的 UI、基于角色的路由和企业级身份集成。
+
+Helix 旨在作为项目的起点使用。Fork 或克隆它,然后在现成的基础上开始构建您自己的业务功能。
+
+## 特性
+
+### 后端(Helix Server)
+
+- **身份认证与授权** — 基于 JWT 的 access token 和 refresh token 流程,配合 Spring Security。支持 Microsoft Entra ID(Azure AD)集成。
+- **基于角色的访问控制** — 通过角色、权限和菜单级访问控制实现细粒度权限管理。
+- **用户与组织管理** — 用户、部门、职位和角色的完整增删改查。
+- **菜单管理** — 层级菜单树,支持按角色配置可见性。
+- **资产管理** — 文件上传至 AWS S3,支持 CDN 前缀处理。
+- **设置管理** — 类型化的应用配置项持久化至数据库。
+- **验证码集成** — 登录和注册流程中的图形验证码校验。
+- **Redis 缓存** — 高性能缓存,支持可配置 TTL 和自定义序列化器。
+- **数据访问** — Spring Data JPA 与 MyBatis 混合持久化方案。
+- **校验** — Bean Validation 分组校验与自定义校验约束。
+
+### 前端(Helix Web)
+
+- **企业级身份认证** — 通过 MSAL 实现 Microsoft Entra ID 登录。可扩展的社交登录提供商架构(Microsoft、Google、GitLab、Slack、Discord、钉钉、飞书、企业微信、邮箱/密码)。
+- **仪表盘布局** — 响应式管理后台,可折叠侧边栏,基于角色的菜单渲染。
+- **用户管理** — 数据表格支持搜索、分页,添加/编辑对话框,角色分配和手机号校验。
+- **角色与菜单管理** — 角色增删改查与权限分配。基于树形的菜单配置。
+- **部门与职位** — 组织层级管理界面。
+- **路由保护** — 在页面加载前检查认证和授权状态。
+- **状态管理** — Redux Toolkit 配合 Redux Persist 实现认证 token 的持久化。
+- **HTTP 客户端** — 基于 Axios 封装的请求客户端,自动注入 JWT token 并在 401 时自动刷新。
+
+## 架构
+
+| 层 | 技术栈 |
+|---|---|
+| **前端** | React 19、TypeScript、Tailwind CSS 4、Ant Design 6、React Router 7、Redux Toolkit、Axios、MSAL |
+| **后端** | Spring Boot 3.5、Java 17、Spring Security、MyBatis、Spring Data JPA |
+| **数据库** | PostgreSQL(使用 Flyway 迁移) |
+| **缓存** | Redis(会话和 token 存储) |
+| **存储** | AWS S3(资源上传) |
+
+前端通过 RESTful JSON API 与后端通信。认证流程使用短有效期的 JWT access token,refresh token 存储在 Redis 中。Microsoft Entra ID 集成在前端通过 MSAL 处理,并在后端进行校验。
+
+## 代码仓库
+
+- [helix-server](https://git.onixbyte.cn/helix/helix-server) — Spring Boot 后端
+- [helix-web](https://git.onixbyte.cn/helix/helix-web) — React 前端
+
+## 快速开始
+
+Helix 是一个模板项目。启动新项目的步骤:
+
+1. Fork 或克隆 `helix-server` 和 `helix-web` 两个仓库。
+2. 在后端配置您的数据库、Redis 和 S3 设置。
+3. 在前端配置您的认证提供商和 API 基础地址。
+4. 启动后端:`./gradlew bootRun`
+5. 启动前端:`pnpm install && pnpm dev`
+
+## 许可证
+
+Helix 是采用 MIT 许可证发布的开源软件。
diff --git a/docs/zh-hans/projects/index.md b/docs/zh-hans/projects/index.md
new file mode 100644
index 0000000..97e0907
--- /dev/null
+++ b/docs/zh-hans/projects/index.md
@@ -0,0 +1,21 @@
+---
+title: 项目
+---
+
+探索由 OnixByte 开发的开源项目。
+
+## 库和工具包
+
+- **[OnixByte Toolbox](/projects/onixbyte-toolbox)** — 面向 Java 应用的开发工具包:AES、哈希、Base64、集合工具、密钥加载器、统计计算器、标识符生成器和泛型元组。
+- **[regions4j](/projects/regions4j)** — 基于 ISO 3166-1 的类型安全 Java 枚举地区元数据,支持 O(1) 查找、E.164 拨号前缀和区域标签。
+- **[Captcha](/projects/captcha)** — 现代化的 Java 验证码生成库,支持水波纹、鱼眼和阴影扭曲效果。
+- **[Calendar Toolbox](/projects/calendar-toolbox)** — 遵循 iCalendar 规范(RFC 5545)创建 `.ics` 文件的 Java 库。
+
+## 全栈应用
+
+- **[Helix](/projects/helix)** — 企业级应用模板,后端使用 Spring Boot,前端使用 React,集成 JWT 认证、RBAC 权限管理、用户与组织管理以及 Microsoft Entra ID 集成。
+- **[Delta Force Guide](/projects/delta-force-guide)** — 为游戏《三角洲行动》提供可搜索枪械改装代码库的 Web 应用,包含 React 单页应用和 Spring Boot REST API。
+
+## Vite 插件
+
+- **[Port Checker](/projects/vite-plugins/port-checker)** — 当 Vite 开发服务器监听浏览器限制的端口时发出警告,避免无响应的连接失败。
diff --git a/docs/zh-hans/projects/onixbyte-toolbox/api.md b/docs/zh-hans/projects/onixbyte-toolbox/api.md
new file mode 100644
index 0000000..ca82acf
--- /dev/null
+++ b/docs/zh-hans/projects/onixbyte-toolbox/api.md
@@ -0,0 +1,209 @@
+---
+title: OnixByte Toolbox API
+---
+
+## 包结构概览
+
+所有模块均在 `com.onixbyte` group ID 下发布。每个模块有自己独立的基础包:
+
+| 模块 | Maven Artifact | 基础包 |
+|---|---|---|
+| Common Toolbox | `common-toolbox` | `com.onixbyte.common` |
+| Crypto Toolbox | `crypto-toolbox` | `com.onixbyte.crypto` |
+| Math Toolbox | `math-toolbox` | `com.onixbyte.math` |
+| Tuple | `tuple` | `com.onixbyte.tuple` |
+| Identity Generator | `identity-generator` | `com.onixbyte.identitygenerator` |
+
+---
+
+## Common Toolbox
+
+### 适配器
+
+`ObjectMapAdapter` — 对象与 Map 之间的转换器。适用于需要键值表示的场景,如序列化或数据转换。
+
+```java
+import com.onixbyte.common.adapter.ObjectMapAdapter;
+```
+
+### 工具类
+
+| 类 | 描述 |
+|---|---|
+| `AesUtil` | AES 对称加密/解密,支持密钥生成 |
+| `Base64Util` | Base64 编解码,支持多种字符集 |
+| `BoolUtil` | 布尔值解析与转换工具 |
+| `BranchUtil` | 条件分支辅助,支持函数式链式调用 |
+| `CollectionUtil` | 集合操作 — 分组、分区、合并 |
+| `HashUtil` | 哈希工具,支持 MD5、SHA-1、SHA-256、SHA-512 |
+| `MapUtil` | Map 构建、合并和转换辅助 |
+| `RangeUtil` | 数值范围操作,支持边界处理 |
+
+**AesUtil 示例:**
+
+```java
+var key = AesUtil.generateKey();
+var encrypted = AesUtil.encrypt("hello world", key);
+var decrypted = AesUtil.decrypt(encrypted, key);
+```
+
+**HashUtil 示例:**
+
+```java
+var md5 = HashUtil.md5("hello world");
+var sha256 = HashUtil.sha256("hello world");
+var fileSha = HashUtil.sha256(new File("data.bin"));
+```
+
+**CollectionUtil 示例:**
+
+```java
+var partitioned = CollectionUtil.partition(list, 100);
+var grouped = CollectionUtil.groupBy(users, User::getDepartment);
+```
+
+---
+
+## Crypto Toolbox
+
+提供了加载 PEM 格式密钥的简洁抽象。支持 RSA 和 ECDSA 算法。
+
+### 密钥加载器
+
+| 类 | 描述 |
+|---|---|
+| `RSAPrivateKeyLoader` | 从 PEM 字符串加载 RSA 私钥 |
+| `RSAPublicKeyLoader` | 从 PEM 字符串加载 RSA 公钥 |
+| `ECPrivateKeyLoader` | 从 PEM 字符串加载 ECDSA 私钥 |
+| `ECPublicKeyLoader` | 从 PEM 字符串加载 ECDSA 公钥 |
+
+所有密钥加载器实现 `PrivateKeyLoader` 或 `PublicKeyLoader` 接口。
+
+**RSA 示例:**
+
+```java
+var privateKey = new RSAPrivateKeyLoader().load(pemString);
+var publicKey = new RSAPublicKeyLoader().load(pemString);
+```
+
+**ECDSA 示例:**
+
+```java
+var ecPrivateKey = new ECPrivateKeyLoader().load(pemString);
+var ecPublicKey = new ECPublicKeyLoader().load(pemString);
+```
+
+### 工具类
+
+`CryptoUtil` — 提供便捷的数字签名生成和验证方法,以及通用密码学辅助功能。
+
+### 异常
+
+| 类 | 描述 |
+|---|---|
+| `KeyLoadingException` | PEM 格式密钥解析失败时抛出 |
+
+---
+
+## Math Toolbox
+
+用于处理数值数据集的统计计算工具。
+
+### 核心类
+
+| 类 | 描述 |
+|---|---|
+| `Calculator` | 统计计算器 — 均值、中位数、方差、标准差、总和、最小值、最大值 |
+| `PercentileCalculator` | 百分位数计算器,支持可配置的插值策略 |
+
+**Calculator 示例:**
+
+```java
+var stats = new Calculator(Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0));
+double mean = stats.getMean();
+double median = stats.getMedian();
+double stdDev = stats.getStandardDeviation();
+```
+
+**PercentileCalculator 示例:**
+
+```java
+var calculator = new PercentileCalculator(data);
+double p95 = calculator.calculate(95);
+double p99 = calculator.calculate(99);
+```
+
+### 数据模型
+
+| 类 | 描述 |
+|---|---|
+| `QuartileBounds` | 包含 Q1、中位数(Q2)、Q3 值及 IQR 和须线边界 |
+
+---
+
+## Tuple
+
+轻量级泛型元组类型,适用于需要返回多个值但无需定义专用类的场景。
+
+### 类
+
+| 类 | 类型参数 | 可变性 |
+|---|---|---|
+| `Tuple` | 两个元素 | 可变 |
+| `ImmutableTuple` | 两个元素 | 不可变 |
+| `Triple` | 三个元素 | 可变 |
+| `ImmutableTriple` | 三个元素 | 不可变 |
+
+**示例:**
+
+```java
+var pair = Tuple.of("key", 42);
+var triple = Triple.of("id", "name", 100);
+var immutable = ImmutableTuple.of("constant", true);
+
+// 访问器
+String first = pair.getFirst();
+Integer second = pair.getSecond();
+
+// 三元组访问器
+String a = triple.getFirst();
+String b = triple.getSecond();
+Integer c = triple.getThird();
+```
+
+---
+
+## Identity Generator
+
+生成适用于数据库主键或分布式 ID 的唯一标识符。
+
+### 接口
+
+`IdentityGenerator` — 生成类型为 `T` 的标识符。
+
+### 实现
+
+| 类 | 描述 |
+|---|---|
+| `SequentialUuidGenerator` | 生成时间排序的顺序 UUID(优化数据库索引性能) |
+| `SnowflakeIdentityGenerator` | 雪花算法分布式唯一 ID 生成 |
+
+**顺序 UUID:**
+
+```java
+var generator = new SequentialUuidGenerator();
+UUID id = generator.nextId(); // 时间排序 UUID,对 B-tree 友好
+```
+
+**雪花:**
+
+```java
+var generator = new SnowflakeIdentityGenerator(workerId, datacenterId);
+long id = generator.nextId(); // 64 位雪花 ID
+```
+
+### 异常
+
+| 类 | 描述 |
+|---|---|
+| `TimingException` | 系统时钟回拨时抛出,保证 ID 唯一性不受影响 |
diff --git a/docs/zh-hans/projects/onixbyte-toolbox/index.mdx b/docs/zh-hans/projects/onixbyte-toolbox/index.mdx
new file mode 100644
index 0000000..e42f450
--- /dev/null
+++ b/docs/zh-hans/projects/onixbyte-toolbox/index.mdx
@@ -0,0 +1,54 @@
+---
+title: OnixByte Toolbox
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## 介绍
+
+OnixByte Toolbox 是一个面向 Java 应用的开发工具包,提供了一系列便捷、可复用的工具,帮助开发者高效编写代码。它由 OnixByte 设计和维护,采用 monorepo 架构,包含多个专用库,每个库解决一个特定的开发需求 — 从通用工具类和密码学,到数学计算和标识符生成。
+
+该工具包已发布到 Maven Central,使用 `com.onixbyte` 作为 group ID。每个模块独立版本管理,可在任何 Java 17+ 项目中使用。
+
+## 模块
+
+| 模块 | Artifact ID | 描述 |
+|--------------------|----------------------|-----------------------------------|
+| Common Toolbox | `common-toolbox` | 日常工具类 — AES 加密、哈希、Base64、集合、分支、范围 |
+| Crypto Toolbox | `crypto-toolbox` | RSA 和 ECDSA 算法的公私钥加载 |
+| Math Toolbox | `math-toolbox` | 统计计算、百分位数分析、四分位数计算 |
+| Tuple | `tuple` | 泛型二元组和三元组,含不可变版本 |
+| Identity Generator | `identity-generator` | 雪花算法和顺序 UUID 唯一标识符生成 |
+| Version Catalogue | `version-catalogue` | OnixByte 项目的集中式 Gradle 版本目录 |
+
+## 安装
+
+在构建配置中添加所需模块的依赖:
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:$artefactId:$version")
+ }
+ ```
+
+
+
+ ```xml title="pom.xml"
+
+ com.onixbyte
+ ${artefactId}
+ ${version}
+
+ ```
+
+
+
+## 要求
+
+- Java 17 或更高版本
+
+## 许可证
+
+OnixByte Toolbox 是采用 MIT 许可证发布的开源软件。
diff --git a/docs/zh-hans/projects/regions4j/index.mdx b/docs/zh-hans/projects/regions4j/index.mdx
new file mode 100644
index 0000000..fdbd104
--- /dev/null
+++ b/docs/zh-hans/projects/regions4j/index.mdx
@@ -0,0 +1,104 @@
+---
+title: Regions for Java
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## 介绍
+
+**regions4j** 是一个轻量级、类型安全的 Java 库,基于 ISO 3166-1 标准提供全面的世界地区元数据。它旨在简化 Java 企业应用中的国际化(i18n)、电信路由和地区数据管理工作。
+
+该库将每个 ISO 3166-1 国家和地区建模为枚举常量,使您在引用地区时获得编译期安全性和 IDE 自动补全支持。凭借内置的 O(1) 查找、零外部依赖和 Java 8 兼容性,它适用于任何规模的项目 — 从微服务到整体式企业系统。
+
+## 特性
+
+- **ISO 3166-1 合规** — 完整支持所有已分配国家和地区的 Alpha-2(`abbreviation`)和 Alpha-3(`code`)格式。
+- **电信元数据** — 包含每个地区的 E.164 国际拨号前缀。
+- **区域支持** — 每个地区提供默认的区域标签(如 `zh_HK`、`en_US`、`en_GB` 等),辅助 i18n 工作流。
+- **高性能** — 线程安全、不可变的内部哈希映射提供常量时间的缩写或代码查找。
+- **零依赖** — 纯 Java 库,无任何外部依赖。
+- **日历化版本管理** — 版本号采用 `YYYY.MM` 格式(如 `2025.12`),以透明地反映底层 ISO 数据的新鲜度,而非语义化版本号。
+
+## 核心数据模型
+
+每个地区暴露四个属性:
+
+| 属性 | 类型 | 描述 | 示例 |
+|---|---|---|---|
+| `abbreviation` | String | ISO 3166-1 alpha-2 缩写 | `HK`、`US`、`GB`、`RU` |
+| `code` | String | ISO 3166-1 alpha-3 代码 | `HKG`、`USA`、`GBR`、`RUS` |
+| `callingCode` | String | E.164 国际拨号前缀 | `852`、`1`、`44`、`7` |
+| `locale` | String | 默认语言和地区标签 | `zh_HK`、`en_US`、`en_GB`、`ru_RU` |
+
+## 安装
+
+
+
+ ```kotlin title="build.gradle.kts"
+ dependencies {
+ implementation("com.onixbyte:regions4j:$version")
+ }
+ ```
+
+
+
+ ```xml title="pom.xml"
+
+ com.onixbyte
+ regions4j
+ ${version}
+
+ ```
+
+
+
+> **版本说明:** 该库使用日历化版本管理(`YYYY.MM`)而非语义化版本号。版本字符串如 `2025.12` 可以直观地告诉您地区数据反映的是 2025 年 12 月的 ISO 3166-1 状态。
+
+## 使用
+
+### 直接访问
+
+通过枚举常量直接引用任何地区:
+
+```java
+Region uk = Region.UNITED_KINGDOM;
+
+uk.getAbbreviation(); // "GB"
+uk.getCode(); // "GBR"
+uk.getDialCode(); // "44"
+uk.getLocale(); // "en_GB"
+```
+
+### 高效查找
+
+从字符串输入中查找地区 — 非常适合处理 Web 请求、API 负载或数据库记录:
+
+```java
+// 按 Alpha-2 缩写查找(区分大小写)
+Region region = Region.fromAbbreviation("HK");
+
+// 按 Alpha-3 代码查找(不区分大小写)
+Region region = Region.fromCode("HKG");
+```
+
+### Java Locale 集成
+
+将地区的 locale 字符串转换为 `java.util.Locale` 以配合标准 Java i18n API 使用:
+
+```java
+Region region = Region.CHINA;
+Locale javaLocale = Locale.forLanguageTag(region.getLocale().replace("_", "-"));
+javaLocale.getDisplayCountry(Locale.UK); // "China"
+```
+
+## 性能
+
+首次访问时,库会将所有地区初始化到不可变的 `HashMap` 结构中。后续通过 `fromAbbreviation()` 和 `fromCode()` 进行的查找均为线程安全且以常量时间运行 — 适用于高吞吐量的请求路径。
+
+## 要求
+
+- Java 8 或更高版本
+
+## 许可证
+
+regions4j 是采用 MIT 许可证发布的开源软件。
diff --git a/docs/zh-hans/projects/vite-plugins/index.mdx b/docs/zh-hans/projects/vite-plugins/index.mdx
new file mode 100644
index 0000000..07bfebc
--- /dev/null
+++ b/docs/zh-hans/projects/vite-plugins/index.mdx
@@ -0,0 +1,11 @@
+---
+title: Vite 插件
+---
+
+## 概览
+
+由 OnixByte 开发和维护的 Vite 插件合集。每个插件旨在解决 Vite 开发工作流中的特定问题 — 轻量级、零依赖、即插即用。
+
+## 可用插件
+
+- **[Port Checker](/projects/vite-plugins/port-checker)** — 当开发服务器监听浏览器限制的端口(依据 Fetch 规范)时发出警告,帮助您避免无响应的连接失败。
diff --git a/docs/zh-hans/projects/vite-plugins/port-checker/index.mdx b/docs/zh-hans/projects/vite-plugins/port-checker/index.mdx
new file mode 100644
index 0000000..4af0052
--- /dev/null
+++ b/docs/zh-hans/projects/vite-plugins/port-checker/index.mdx
@@ -0,0 +1,67 @@
+---
+title: Port Checker
+---
+
+import { Tabs, Tab } from "@rspress/core/theme"
+
+## 介绍
+
+**vite-plugin-port-checker** 是一个轻量级的 Vite 插件,可在开发服务器监听被常见浏览器屏蔽的端口时发出警告。Chrome 和 Firefox 等浏览器维护了一份[受限制端口列表](https://fetch.spec.whatwg.org/#port-blocking) — 这些端口通常与 SMTP、SSH 和 DNS 等知名协议关联 — 并拒绝连接这些端口。如果不小心将开发服务器运行在这些端口上,会导致令人困惑的"连接被拒绝"或"已被屏蔽"错误,且没有任何明确的解释。
+
+该插件会在启动时检测到这种情况,并向控制台打印一条清晰且带有颜色标记的警告,建议您修改 Vite 配置中的 `server.port` 设置。
+
+## 特性
+
+- **自动检测** — 对照完整的 Fetch 规范端口屏蔽列表(68 个受限端口)检查开发服务器端口。
+- **清晰的警告** — 黄色高亮控制台输出,并提供可操作的指导。
+- **零配置** — 开箱即用,无需设置任何选项。
+- **轻量级** — 单文件插件,除 Vite 本身外无任何依赖。
+
+## 安装
+
+
+
+ ```bash
+ npm install vite-plugin-port-checker -D
+ ```
+
+
+ ```bash
+ pnpm add vite-plugin-port-checker -D
+ ```
+
+
+
+## 使用
+
+在 `vite.config.ts` 中添加插件:
+
+```ts title="vite.config.ts"
+import { defineConfig } from "vite"
+import checkRestrictedPort from "vite-plugin-port-checker"
+
+export default defineConfig({
+ plugins: [checkRestrictedPort()],
+})
+```
+
+当开发服务器启动在受限端口(如 25、22 或 53 端口)时,您将看到:
+
+```
+[Warning] The current listening port 25 is categorised as a restricted port
+by most browsers. This may prevent you from accessing the application.
+Please consider changing the port in your 'vite.config.ts' or 'vite.config.js'
+via 'server.port'.
+```
+
+## 工作原理
+
+该插件通过钩入 Vite 的 `configureServer` 生命周期工作。当 HTTP 服务器触发 `listening` 事件后,插件检查绑定的端口号,并与 [Fetch 规范](https://fetch.spec.whatwg.org/#port-blocking)中定义的 68 个受限端口进行比对。如果匹配,则通过黄色的 `console.warn` 消息提醒开发者。
+
+## 要求
+
+- Vite 3.0.0 或更高版本
+
+## 许可证
+
+vite-plugin-port-checker 是采用 MIT 许可证发布的开源软件。
diff --git a/i18n.json b/i18n.json
index 9fb0532..de46ba9 100644
--- a/i18n.json
+++ b/i18n.json
@@ -112,7 +112,7 @@
"zh-hans": "折叠"
},
"blogs": {
- "en-gb": "Blogs",
+ "en-gb": "Blog",
"zh-hans": "博客"
},
"notifications": {