Mementomori.social
Mementomori.social

Instance features

Mementomori.social is not your yet another instance with defaults. It is packed with small, but groundbreaking modifications. This page lists all of them.

On top of the regular Mastodon features like per-post visibility, content warnings and real time feed, Mementomori.social has the following features.

Mastodon Bird UI

Mastodon Bird UI is something I've been designing since March, 2023. It's a new kind of modern Mastodon UI, inspired by Twitter UI in its good era. Yes, I know, the word bird and Twitter may be a turn-off for some, but I actually like what Twitter made to its UI in 2021. The changes after that are not that good, so I took the UI in 2021 as an inspiration and created this:

Screenshot of Mastodon Bird UI with main feed active, Forbes posting Home Run Derby Odds: Here's How The Derby Works - And Who Has The Best Change of Winning

The UI can be found on GitHub and its updates can be followed under hashtags #BirdUI and #MastodonBirdUI on Mastodon.

ronilaukkarinen/mastodon-bird-ui

Repository on GitHub

Ranked For You -feed

Algorithmic home feed as an opt-in experiment. Same idea as Twitter's open sourced ranking pipeline (candidates, score, mix) but stripped to what a single instance actually needs. Chronological stays the default, nothing changes if you do not turn this on.

mementomori-social/mastodon #4

Pull request on GitHub

Multiple Site themes

On Mementomori.social you get to choose from two major themes with variations:

  • Original Mastodon UI (Dark, Light and High contrast versions)
  • Mastodon Bird UI (Dark, Light, High contrast, Ultra accessible versions)

Ultra accessible theme

On our instance we have focused to accessibility with a special touch towards users with acromatopsia, vision impairment or age vision. Mastodon Bird UI (Ultra accessible) theme consists of features such as

  • Hashtags, links and mentions are in different colors
  • Contrast is even starker than in default High contrast themes, black background with white text
  • Font sizes are much larger throughout the site
  • The font size is even larger on mobile
  • All input boxes and modals have color to distinguish them from the background
  • All colors are tested with a contrast checker and with a real person so that they have sufficient contrast ratios

Screenshot of an ultra accessible theme with larger font sizes, better contrast and so forth

Default Mastodon has small link previews for URLs. I wanted to make them big and was inspired by this ongoing feature request. This is actually now in the Mastodon core, so our instance just follows the core card, but styles it to be more minimal.

Bigger Twitter-like link previewsmastodon/mastodon@e97868a
--- app/javascript/mastodon/features/status/components/card.jsx
@@ -165,8 +165,8 @@ export default class Card extends PureComponent {
     const description = (
       <div className='status-card__content' lang={language}>
         {title}
-        {!(horizontal || compact) && <p className='status-card__description' title={card.get('description')}>{card.get('description')}</p>}
         <span className='status-card__host'>{provider}</span>
+        {<p className='status-card__description' title={card.get('description')}>{card.get('description')}</p>}
       </div>
     );
 
@@ -231,7 +231,7 @@ export default class Card extends PureComponent {
       return (
         <div className={className} ref={this.setRef} onClick={revealed ? null : this.handleReveal} role={revealed ? 'button' : null}>
           {embed}
-          {!compact && description}
+          {description}
         </div>
       );
     } else if (card.get('image')) {

Bigger Twitter-like link previews in a screenshot

Top and bottom bar scroll out of the way

A subtle change, suggested by ikkeT. See the post presenting it. See JavaScript changes here and Style changes here.

Video presenting the scrolling animation

Allow max. 15 hashtags in the advanced interface columns

The default Mastodon Advanced interface allows 4 hashtags per column. We allow 15. There is a closed issue that is still an issue on 4.1.4.

Allow max 15 hashtags per view in advanced interfacemastodon/mastodon@d8026ca
--- app/javascript/mastodon/features/hashtag_timeline/components/column_settings.jsx
@@ -48,7 +48,7 @@ class ColumnSettings extends PureComponent {
 
     // Prevent changes that add more than 4 tags, but allow removing
     // tags that were already added before
-    if ((value.length > 4) && !(value < oldValue)) {
+    if ((value.length > 15) && !(value < oldValue)) {
       return;
     }
 
--- app/models/tag_feed.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class TagFeed < PublicFeed
-  LIMIT_PER_MODE = 4
+  LIMIT_PER_MODE = 15
 
   # @param [Tag] tag
   # @param [Account] account

Show case of adding 6 example hashtags in the column

Lots of custom emojis

Mementomori.social has a lot of custom emojis. You can also request your own by sending a post to @rolle. Good emoji source: Slackmojis.

A GIF animation video scrolling all the wonderful emojis

Polls with 15 options and 150 character limit per option

Default Mastodon allows max. 4 options and 50 character limit per option. I have increased them so that posting polls is not too strict.

Increase poll options to 15 and character length to 150mastodon/mastodon@9f58a0d
--- app/javascript/mastodon/features/compose/components/poll_form.jsx
@@ -164,7 +164,7 @@ class PollForm extends ImmutablePureComponent {
         </ul>
 
         <div className='poll__footer'>
-          <button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
+          <button type='button' disabled={options.size >= 15} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
 
           {/* eslint-disable-next-line jsx-a11y/no-onchange */}
           <select value={expiresIn} onChange={this.handleSelectDuration}>
--- app/validators/poll_validator.rb
@@ -1,8 +1,8 @@
 # frozen_string_literal: true
 
 class PollValidator < ActiveModel::Validator
-  MAX_OPTIONS      = 4
-  MAX_OPTION_CHARS = 50
+  MAX_OPTIONS      = 15
+  MAX_OPTION_CHARS = 150
   MAX_EXPIRATION   = 1.month.freeze
   MIN_EXPIRATION   = 5.minutes.freeze
 

Posted poll presented with more than 4 choices, compose form example with 12 choices and long answer.

Increased character limit to 10000 characters

Mastodon's default is 500. We have 10000. Never have to think about the lenght of your posts any more.

Increase character limit in posts from 500 to 10000mastodon/mastodon@9a0e13d
--- app/javascript/mastodon/features/compose/components/compose_form.jsx
@@ -100,7 +100,7 @@ class ComposeForm extends ImmutablePureComponent {
     const fulltext = this.getFulltextForCharacterCounting();
     const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
 
-    return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia));
+    return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 10000 || (isOnlyWhitespace && !anyMedia));
   };
 
   handleSubmit = (e) => {
@@ -298,7 +298,7 @@ class ComposeForm extends ImmutablePureComponent {
             </div>
 
             <div className='character-counter__wrapper'>
-              <CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} />
+              <CharacterCounter max={10000} text={this.getFulltextForCharacterCounting()} />
             </div>
           </div>
         </div>
--- app/serializers/rest/instance_serializer.rb
@@ -11,7 +11,7 @@ class ContactSerializer < ActiveModel::Serializer
 
   attributes :domain, :title, :version, :source_url, :description,
              :usage, :thumbnail, :languages, :configuration,
-             :registrations
+             :registrations, :max_toot_chars
 
   has_one :contact, serializer: ContactSerializer
   has_many :rules, serializer: REST::RuleSerializer
@@ -89,6 +89,10 @@ def registrations
     }
   end
 
+  def max_toot_chars
+    10_000
+  end
+
   private
 
   def registrations_enabled?
View full diff on GitHub

Show full comment, boost and fav amounts in posts instead of just "1+" or nothing

The Vanilla Mastodon doesn't show these amounts and will likely never show them natively as per this comment. However as an OCD person the metrics matter so on Mementomori.social you'll see full amount of comments. (Related issue on Mastodon)

Metrics show up on Explore, Bookmarks and Favourites from 31st of July, 2023. Comment count is accurate everywhere.

Please note, currently this is reversed to default due to unreliable method.

Metrics shown on home feed

Add counters everywhereronilaukkarinen/mastodon@aaec9c8
--- app/javascript/mastodon/components/status_action_bar.jsx
@@ -361,9 +361,9 @@ class StatusActionBar extends ImmutablePureComponent {
 
     return (
       <div className='status__action-bar'>
-        <IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} obfuscateCount />
-        <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
-        <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
+        <IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
+        <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
+        <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
         <IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
 
         {filterButton}
--- app/javascript/mastodon/features/bookmarked_statuses/index.jsx
@@ -98,6 +98,7 @@ class Bookmarks extends ImmutablePureComponent {
           onLoadMore={this.handleLoadMore}
           emptyMessage={emptyMessage}
           bindToDocument={!multiColumn}
+          withCounters
         />
 
         <Helmet>
--- app/javascript/mastodon/features/favourited_statuses/index.jsx
@@ -98,6 +98,7 @@ class Favourites extends ImmutablePureComponent {
           onLoadMore={this.handleLoadMore}
           emptyMessage={emptyMessage}
           bindToDocument={!multiColumn}
+          withCounters
         />
 
         <Helmet>
--- app/javascript/mastodon/features/pinned_statuses/index.jsx
@@ -57,6 +57,7 @@ class PinnedStatuses extends ImmutablePureComponent {
           scrollKey='pinned_statuses'
           hasMore={hasMore}
           bindToDocument={!multiColumn}
+          withCounters
         />
         <Helmet>
View full diff on GitHub
Show full comment count in posts instead of just "1+"mastodon/mastodon@70c748b
--- app/javascript/mastodon/components/animated_number.tsx
@@ -12,7 +12,7 @@ const obfuscatedCount = (count: number) => {
   } else if (count <= 1) {
     return count;
   } else {
-    return '1+';
+    return count;
   }
 };
 

Extended full-text post and account search

By default Mastodon searches only for your own posts and the ones you have answered to, if that. Search provided by Elasticsearch. On Mementomori.social you can search all posts the Mastodon instance is aware of, from the users who want to be found ("Include public posts in search results" enabled on settings). This is actually now in the Mastodon core, so our instance just follows the core feature.

Mastodon search screenshot for "politics", last found post 6min ago.

VyrCossont/mastodon #8

Pull request on GitHub

DeepL translations

For posts other than your language (set in profile) a "Translate" link is shown, by pressing it you can see accurate translation provided by DeepL.

DeepL translate feature screenshot

500 posts on the Explore tab

By default Mastodon shows 100 posts on the Explore tab. We show 500.

Increase the batch size of trending posts to 500ronilaukkarinen/mastodon@62c3258
--- app/models/trends/statuses.rb
@@ -3,7 +3,7 @@
 class Trends::Statuses < Trends::Base
   PREFIX = 'trending_statuses'
 
-  BATCH_SIZE = 100
+  BATCH_SIZE = 500
 
   self.default_options = {
     threshold: 5,

Snow during winter holidays

Let it snow! ❄️ See update.

Let it snow! ❄️ronilaukkarinen/mastodon@9bf1563
--- app/javascript/mastodon/common.js
@@ -10,6 +10,115 @@ export function start() {
   }
 }
 
+function animate(ctx, snowflakes, canvas, maxFlakes) {
+  ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+  // Add new snowflake if we haven't reached the maximum
+  if (snowflakes.length < maxFlakes && Math.random() < 0.05) {  // 5% chance each frame to add a new flake
+    snowflakes.push({
+      x: Math.random() * canvas.width,
+      y: 0,  // Start from top
+      radius: Math.random() * 7 + 3,
+      speed: Math.random() * 0.5 + 0.3,
+      opacity: Math.random() * 0.6 + 0.4
+    });
+  }
+
+  snowflakes.forEach(flake => {
+    // Draw snowflake shape
+    ctx.save();
+    ctx.beginPath();
+    for (let i = 0; i < 6; i++) {
+      ctx.moveTo(flake.x, flake.y);
+      ctx.lineTo(
+        flake.x + Math.cos(Math.PI * 2 * i / 6) * flake.radius,
+        flake.y + Math.sin(Math.PI * 2 * i / 6) * flake.radius
+      );
+    }
+    ctx.strokeStyle = `rgba(255, 255, 255, ${flake.opacity})`;
+    ctx.lineWidth = 1.5;
+    ctx.stroke();
+    ctx.restore();
+
+    // Update position with gentler movement
+    flake.x += Math.sin(flake.y / 50) * 0.3;
+    flake.y += flake.speed * 0.5;
+
+    if (flake.y > canvas.height) {
View full diff on GitHub

Implement fix for m.youtube.com and youtu.be previewsronilaukkarinen/mastodon@ccd4063
--- app/services/fetch_link_card_service.rb
@@ -57,7 +57,11 @@ def html
     headers = {
       'Accept' => 'text/html',
       'Accept-Language' => "#{I18n.default_locale}, *;q=0.5",
-      'User-Agent' => "#{Mastodon::Version.user_agent} Bot",
+      'User-Agent' => if @url.match?(/\b(youtube\.com|youtu\.be|m\.youtube\.com)\b/)
+                        "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discord.com)"
+                      else
+                        "#{Mastodon::Version.user_agent} Bot"
+                      end
     }
 
     @html = Request.new(:get, @url).add_headers(headers).perform do |res|

In the core version, only www.youtube.com previews work. On mementomori.social, all YouTube link variations generate a preview.

Autoplay gifs and videos without sound if reduced motion is disabled

Vanilla Mastodon doesn't have a feature for this, gifs and videos are not autoplaying - especially for guests.

Autoplay gifs for logged out usersmementomori-social/mastodon@0878938
--- app/models/user_settings.rb
@@ -35,7 +35,7 @@ class KeyError < Error; end
     setting :reduce_motion, default: false
     setting :expand_content_warnings, default: false
     setting :display_media, default: 'default', in: %w(default show_all hide_all)
-    setting :auto_play, default: false
+    setting :auto_play, default: true
     setting :emoji_style, default: 'auto', in: %w(auto native twemoji)
   end
 
--- config/settings.yml
@@ -33,6 +33,8 @@ defaults: &defaults
   backups_retention_period: 7
   captcha_enabled: false
   allow_referrer_origin: false
+  auto_play_gif: true
+  reduce_motion: false
 
 development:
   <<: *defaults
Introduce auto-play videos muted featuremementomori-social/mastodon@ffb941a
--- app/javascript/mastodon/components/gif.tsx
@@ -1,12 +1,12 @@
 import { useHovering } from 'mastodon/hooks/useHovering';
-import { autoPlayGif } from 'mastodon/initial_state';
+import { autoPlayGif, reduceMotion } from 'mastodon/initial_state';
 
 export const GIF: React.FC<{
   src: string;
   staticSrc: string;
   className: string;
   animate?: boolean;
-}> = ({ src, staticSrc, className, animate = autoPlayGif }) => {
+}> = ({ src, staticSrc, className, animate = autoPlayGif || !reduceMotion }) => {
   const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
 
   return (
--- app/javascript/mastodon/components/media_gallery.jsx
@@ -15,7 +15,7 @@ import { Blurhash } from 'mastodon/components/blurhash';
 import { SpoilerButton } from 'mastodon/components/spoiler_button';
 import { formatTime } from 'mastodon/features/video';
 
-import { autoPlayGif, displayMedia, useBlurhash } from '../initial_state';
+import { autoPlayGif, displayMedia, reduceMotion, useBlurhash } from '../initial_state';
 
 class Item extends PureComponent {
 
@@ -56,7 +56,7 @@ class Item extends PureComponent {
   };
 
   getAutoPlay() {
-    return this.props.autoplay || autoPlayGif;
+    return this.props.autoplay || autoPlayGif || !reduceMotion;
   }
 
   hoverToPlay () {
--- app/javascript/mastodon/features/account_gallery/components/media_item.tsx
@@ -9,7 +9,7 @@ import { AltTextBadge } from 'mastodon/components/alt_text_badge';
 import { Blurhash } from 'mastodon/components/blurhash';
 import { Icon } from 'mastodon/components/icon';
 import { formatTime } from 'mastodon/features/video';
View full diff on GitHub

Last updated 2 hours ago by Rolle Laukkarinen

On this page