<feed xmlns='http://www.w3.org/2005/Atom'>
<title>LunaticChat.git/website, branch main</title>
<subtitle>A next-generation chat plugin for Paper, Folia and Velocity.
</subtitle>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/'/>
<entry>
<title>docs: name the anthy engine in the project description</title>
<updated>2026-10-11T03:31:28+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-11T03:31:28+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=d06ef045d846a751d92936c223ac8f2d2f71efb4'/>
<id>d06ef045d846a751d92936c223ac8f2d2f71efb4</id>
<content type='text'>
The tagline and both plugin descriptors now say that romaji conversion can run
inside the server through anthy, so the engine is visible wherever the project
describes itself: the README, the website hero and meta description, the API
documentation, and the Paper and Velocity plugin descriptors.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The tagline and both plugin descriptors now say that romaji conversion can run
inside the server through anthy, so the engine is visible wherever the project
describes itself: the README, the website hero and meta description, the API
documentation, and the Paper and Velocity plugin descriptors.
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(conversion): run anthy in-process through WebAssembly</title>
<updated>2026-10-11T02:53:22+00:00</updated>
<author>
<name>Charlie Root</name>
<email>root@dangofactory.local</email>
</author>
<published>2026-10-11T02:53:22+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=a1035c2f2007846d3cf5d07047f47a30815838e6'/>
<id>a1035c2f2007846d3cf5d07047f47a30815838e6</id>
<content type='text'>
Add a second engine for romaji-to-Japanese conversion that leaves the process
alone: anthy, compiled to a WebAssembly module and executed in the JVM by
Chicory's build-time AOT, so conversion needs no outbound request.

anthy/ carries the module sources, the WASI shims, the reproducible build
script, the committed AOT output and the dictionary (~23 MB, extracted into
the plugin data folder on first start; an existing file is left alone).
features.japaneseConversion.engine selects "google" or "anthy", and the anthy
block adds dictionary, workDirectory and sentenceLevel.

RomanjiConverter now sits on a KanjiConverter interface, so a whole message is
handed to the engine at once - anthy segments and reorders a sentence instead
of converting word by word - and the conversion cache is keyed by that
sentence. The engine tests drive the real module, the dictionary tests cover
the extraction, and everything else keeps running on the existing fakes.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add a second engine for romaji-to-Japanese conversion that leaves the process
alone: anthy, compiled to a WebAssembly module and executed in the JVM by
Chicory's build-time AOT, so conversion needs no outbound request.

anthy/ carries the module sources, the WASI shims, the reproducible build
script, the committed AOT output and the dictionary (~23 MB, extracted into
the plugin data folder on first start; an existing file is left alone).
features.japaneseConversion.engine selects "google" or "anthy", and the anthy
block adds dictionary, workDirectory and sentenceLevel.

RomanjiConverter now sits on a KanjiConverter interface, so a whole message is
handed to the engine at once - anthy segments and reorders a sentence instead
of converting word by word - and the conversion cache is keyed by that
sentence. The engine tests drive the real module, the dictionary tests cover
the extraction, and everything else keeps running on the existing fakes.
</pre>
</div>
</content>
</entry>
<entry>
<title>chore(deps): update dependency @biomejs/biome to v2.5.15 (#321)</title>
<updated>2026-10-01T04:50:39+00:00</updated>
<author>
<name>renovate[bot]</name>
<email>29139614+renovate[bot]@users.noreply.github.com</email>
</author>
<published>2026-10-01T04:50:39+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=e95b20c4926307a26813b967d75c639e207551e0'/>
<id>e95b20c4926307a26813b967d75c639e207551e0</id>
<content type='text'>
Co-authored-by: renovate[bot] &lt;29139614+renovate[bot]@users.noreply.github.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Co-authored-by: renovate[bot] &lt;29139614+renovate[bot]@users.noreply.github.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>docs(changelog): add release notes for paper v1.5.0 and velocity v1.3.1</title>
<updated>2026-09-28T14:58:00+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T14:58:00+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=50c2d55be2a85fe61c9694a27019031245dd1e6c'/>
<id>50c2d55be2a85fe61c9694a27019031245dd1e6c</id>
<content type='text'>
The GitHub Release and the Modrinth version both link to these pages, so
they have to be deployed before the tags are pushed.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The GitHub Release and the Modrinth version both link to these pages, so
they have to be deployed before the tags are pushed.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat: carry the sender's world in cross-server direct messages</title>
<updated>2026-09-28T14:43:14+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T14:43:14+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=388ae4ef14ec620e6f1fe2ce8a8ea8e3a816d10d'/>
<id>388ae4ef14ec620e6f1fe2ce8a8ea8e3a816d10d</id>
<content type='text'>
{world} rendered empty for a direct message from another server, which
left formats like "({world})" showing a bare pair of brackets. The relay
now carries the sender's world as an optional field, so this is a PATCH
bump (protocol 1.0.2) and either side can be updated first; an older
sender or proxy still yields an empty value.

The world is read once per message, so the sender, the spies and the
relayed copy can no longer disagree if the sender changes worlds mid-way.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
{world} rendered empty for a direct message from another server, which
left formats like "({world})" showing a bare pair of brackets. The relay
now carries the sender's world as an optional field, so this is a PATCH
bump (protocol 1.0.2) and either side can be updated first; an older
sender or proxy still yields an empty value.

The world is read once per message, so the sender, the spies and the
relayed copy can no longer disagree if the sender changes worlds mid-way.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(paper): splice display names as components and share role labels</title>
<updated>2026-09-28T14:43:13+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T14:43:13+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=a22fce70db7b43aadd8baa42e87a4430a8b1e05f'/>
<id>a22fce70db7b43aadd8baa42e87a4430a8b1e05f</id>
<content type='text'>
Serializing the display name into the legacy text let its color run into
everything after it, and legacy text cannot hold hex colors or hover and
click events, so names styled by other plugins came out wrong. The name is
now spliced into the parsed component instead.

{role} is resolved only when the format uses it, since the default
formats do not and it costs a member scan and a lookup per message.
/lc channel status now shows the same localized role names instead of a
second, hard-coded [OWNER] / [MOD] vocabulary that only one of the two
places translated.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Serializing the display name into the legacy text let its color run into
everything after it, and legacy text cannot hold hex colors or hover and
click events, so names styled by other plugins came out wrong. The name is
now spliced into the parsed component instead.

{role} is resolved only when the format uses it, since the default
formats do not and it costs a member scan and a lookup per message.
/lc channel status now shows the same localized role names instead of a
second, hard-coded [OWNER] / [MOD] vocabulary that only one of the two
places translated.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(paper): add world, display_name, channel_id and role chat placeholders</title>
<updated>2026-09-28T14:00:29+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T14:00:29+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=af2feee95e7f6ebaef5466402789917ae65c0796'/>
<id>af2feee95e7f6ebaef5466402789917ae65c0796</id>
<content type='text'>
Operators asked for more of the sender's context in chat formats than the
name alone. {world} covers direct messages and channel chat; the channel
details and the sender's display name and role only exist for channel
chat, so only that format accepts them.

A direct message from another server renders {world} empty: the relay does
not carry the sender's world, and adding it would need a protocol bump and
a coordinated Velocity release for one placeholder. The renderer now
accepts underscores so the snake_case names match as written.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Operators asked for more of the sender's context in chat formats than the
name alone. {world} covers direct messages and channel chat; the channel
details and the sender's display name and role only exist for channel
chat, so only that format accepts them.

A direct message from another server renders {world} empty: the relay does
not carry the sender's world, and adding it would need a protocol bump and
a coordinated Velocity release for one placeholder. The renderer now
accepts underscores so the snake_case names match as written.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor(paper): render chat formats through one placeholder vocabulary</title>
<updated>2026-09-28T13:21:21+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T13:21:21+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=9601f147dd38d5fc93d8fff118794990f44c3766'/>
<id>9601f147dd38d5fc93d8fff118794990f44c3766</id>
<content type='text'>
Placeholder names were spelled as string literals in three handlers, and
each handler also chose its own way of turning the result into a
Component. Adding a placeholder meant finding every call site by hand, with
nothing to catch a format left without its value.

ChatPlaceholder now owns the names, and each format has an entry point whose
parameters are exactly the placeholders it accepts, so the compiler points
at the callers when one is added. Substitution happens in a single pass, so
a value that itself contains "{message}" is no longer replaced again by the
next placeholder. All three formats now deserialize section signs into
styles, which leaves what players see unchanged.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Placeholder names were spelled as string literals in three handlers, and
each handler also chose its own way of turning the result into a
Component. Adding a placeholder meant finding every call site by hand, with
nothing to catch a format left without its value.

ChatPlaceholder now owns the names, and each format has an entry point whose
parameters are exactly the placeholders it accepts, so the compiler points
at the callers when one is added. Substitution happens in a single pass, so
a value that itself contains "{message}" is no longer replaced again by the
next placeholder. All three formats now deserialize section signs into
styles, which leaves what players see unchanged.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: record the tag scheme change and the update checker fix in CHANGELOG</title>
<updated>2026-09-28T12:48:55+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T12:48:55+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=5137d1ec51ba1ae609603a928d4a55ff3d499a0c'/>
<id>5137d1ec51ba1ae609603a928d4a55ff3d499a0c</id>
<content type='text'>
The fix is a bug fix only, so it goes under a v1.4.1 heading. The tag scheme
notes now say "up to v1.4.0" instead of naming v1.5.0, because the next Paper
release is a patch and the boundary would otherwise point at a version that
may never ship.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The fix is a bug fix only, so it goes under a v1.4.1 heading. The tag scheme
notes now say "up to v1.4.0" instead of naming v1.5.0, because the next Paper
release is a patch and the boundary would otherwise point at a version that
may never ship.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>ci: tag each release with exactly one platform</title>
<updated>2026-09-28T12:35:52+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T12:35:52+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=9bb1623c32c80da097f423c1ae3c96aa11372a43'/>
<id>9bb1623c32c80da097f423c1ae3c96aa11372a43</id>
<content type='text'>
A vX.Y.Z tag used to ship both JARs under the Paper version number, so the
Velocity version never appeared in a tag. Changelog download links guessed
paper/ and velocity/ tags that did not exist and returned 404, and the same
JAR resurfaced under several releases.

Paper now releases on vX.Y.Z and Velocity on velocity/vX.Y.Z, which matches
the CHANGELOG.md headings one to one. Paper keeps the bare form rather than
moving to paper/vX.Y.Z because the update checker in already-deployed Paper
builds only understands that form. Both workflows call a shared reusable
workflow, since the two had drifted into near-identical copies.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A vX.Y.Z tag used to ship both JARs under the Paper version number, so the
Velocity version never appeared in a tag. Changelog download links guessed
paper/ and velocity/ tags that did not exist and returned 404, and the same
JAR resurfaced under several releases.

Paper now releases on vX.Y.Z and Velocity on velocity/vX.Y.Z, which matches
the CHANGELOG.md headings one to one. Paper keeps the bare form rather than
moving to paper/vX.Y.Z because the update checker in already-deployed Paper
builds only understands that form. Both workflows call a shared reusable
workflow, since the two had drifted into near-identical copies.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
