Xypter
Xypter

Reputation: 21

How do I completely remove font smoothing from bitmap fonts? Is the solution possible with Javascript?

On my current website, I am trying to render everything pixelated with sprite graphics and pixel fonts to make it look as close to a game as possible. The problem is that Chrome and Firefox like to render pixel fonts differently and there isn't a way to make them look consistent. This especially happens when trying to center the font or use css transform. It always defaults to anti-aliasing it.

Just for reference, here is the font I am trying to render dynamically:

Firefox: Firefox Render Example

Chrome: enter image description here

Notice how it looks crystal clear on Firefox while blurry in Chrome.

I have attempted to try all sorts of css tricks to fix this with no luck, including some methods listed in this interesting Github repo. Then I came across some game development forums where they were discussing using a texture atlas to import their fonts in their games.

Here is an example. In the second half of the page, you can see they are using a sprite sheet with all the font letters laid out, then using code to assign each part to a letter and insert it into their WebGL example. I would like to do the same thing, except in my case have it dynamically reference what I typed and insert it where my example text is.

I'm sure there is a way this could be done in Javascript, or maybe there is another solution somebody else has already come up with that I just haven't thought of yet. Any ideas?

Here is an example of what the code looks like:

:root {
  --multiplication-factor: 1;
  --number-shadow: #002806;
  --text-shadow: #4b4b54;
  --font-size: 16px;
}

@font-face {
  font-family: pixeltiny;
  src: url(https://old.sgxp.me/example/PixelTiny.ttf);
}

body {
  transform: translateZ(0);
}

.sprite-page-container {
  margin: 20px 105px;
}

.sprite-container {
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  padding: 10px;
  min-height: 200px;
  transition: 1s;
}

.sprite-box {  
  width: calc(117px * var(--multiplication-factor));
  height: calc(188px * var(--multiplication-factor));
  background-image: url('https://old.sgxp.me/example/icon_image.svg');
  margin: 10px;
  user-select: none;
  transition: transform ease-in-out .2s;
  text-decoration: none;
  border-radius: 4px;
  box-shadow: 10px 10px 0px rgba(0,0,0,0.7);
  animation: fadein-top .7s;
}

.sprite-box:hover {
  transform: translateY(calc(-5px * var(--multiplication-factor)));
  animation: fadein-top .7s;
}

.sprite-page-container a {
  color: white;
  padding: 0;
}

.sprite-page-container a:hover {
  padding: 0;
  background-image: url("https://old.sgxp.me/example/icon_image.svg");
}

.sprite-page-container a:visited {
  color: white;
}

.sprite-star-container {
  display: flex;
  margin-left: calc(6px * var(--multiplication-factor));
  margin-top: calc(3px * var(--multiplication-factor));
  margin-bottom: calc(-9px * var(--multiplication-factor));
  width: calc(70px * var(--multiplication-factor));
}

.sprite-star {
  height: calc(6px * var(--multiplication-factor));
  width: calc(7px * var(--multiplication-factor));
}

.sprite-star:nth-child(n + 2) {
  margin-left: calc(-1px * var(--multiplication-factor));
}

.sprite-number {
  font-family: 'pixeltiny', monospace;
  font-size: calc(var(--font-size) * var(--multiplication-factor));
  color: white;
  user-select: none;
  display: flex;
  justify-content: right;
  line-height: 0;
  margin-right: calc(6px * var(--multiplication-factor));
  margin-top: calc(3px * var(--multiplication-factor));
  text-shadow: calc(1px * var(--multiplication-factor)) 0px var(--number-shadow), 0px calc(1px * var(--multiplication-factor)) var(--number-shadow), calc(1px * var(--multiplication-factor)) calc(1px * var(--multiplication-factor)) var(--number-shadow);
}

.sprite-text {
  font-family: 'pixeltiny', monospace;
  user-select: none;
  font-size: calc(var(--font-size) * var(--multiplication-factor));
  line-height: calc(7px * var(--multiplication-factor));
  text-align: center;
  color:white;
}

.sprite-title {
  display: flex;
  justify-content: center;
  align-items: center;
  padding-top: calc(4px * var(--multiplication-factor));
  margin-left: calc(5px * var(--multiplication-factor));
  margin-right: calc(10px * var(--multiplication-factor));
  height: calc(15px * var(--multiplication-factor));
  width: calc(109px * var(--multiplication-factor));
  overflow-wrap: anywhere;
}

.sprite-image {
  display: flex;
  justify-content: center;
  align-items: center;
  image-rendering: pixelated;
  pointer-events: none;
  height: calc(71px * var(--multiplication-factor));
  width: calc(103px * var(--multiplication-factor));  
  margin-top: calc(5px * var(--multiplication-factor));
  margin-left: calc(7px * var(--multiplication-factor));
  margin-right: calc(6px * var(--multiplication-factor));
  object-fit: cover;
  overflow: hidden;
}

.sprite-image > img {
  filter: drop-shadow(calc(10px * var(--multiplication-factor)) calc(10px * var(--multiplication-factor)) 0px rgba(0,0,0,0.7));
  transform: scale(calc(1 * var(--multiplication-factor)));
}

.sprite-author {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: calc(-2px * var(--multiplication-factor));
  margin-left: calc(13px * var(--multiplication-factor));
  margin-right: calc(12px * var(--multiplication-factor));
  margin-bottom: calc(0spx * var(--multiplication-factor));
  height: calc(26px * var(--multiplication-factor));
  width: calc(93px * var(--multiplication-factor));
  overflow-wrap: anywhere;
}

.sprite-stats {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  margin-top: calc(4px * var(--multiplication-factor));
  margin-left: calc(24px * var(--multiplication-factor));
  margin-right: calc(3px * var(--multiplication-factor));
  width: calc(110px * var(--multiplication-factor));
}

.sprite-stats:nth-child(n+2) {
  height: calc(5px * var(--multiplication-factor));
}

@keyframes fadein-top {
  0% { opacity: 0; transform: translateY(-50px);}
  50% { opacity: 0; transform: translateY(-50px);}
  100% { opacity: 1; transform: translateY(0); }
}
<div class="sprite-container">
  <a href="" class="sprite-box">
    <div class="sprite-star-container">
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
      <div class="sprite-star"></div>
    </div>
    <div class="sprite-number">001</div>
    <div class="sprite-title">
      <div id="author" class="sprite-text">Example</div>
    </div>
    <div class="sprite-image">
      <img src="" alt="">
    </div>
    <div class="sprite-author">
      <div class="sprite-text">Example</div>
    </div>
    <div class="sprite-stats">
      <div class="sprite-text">Example</div>
    </div>
    <div class="sprite-stats">
      <div class="sprite-text">Example</div>
    </div>
    <div class="sprite-stats">
      <div class="sprite-text">Exmaple</div>
    </div>
    <div class="sprite-stats">
      <div class="sprite-text">Exmaple</div>
    </div>
  </a>
 </div>

As you can see, I am dynamically putting the example text over my svg image. Everything in the svg looks fine, but when I insert my text Chrome renders it with this weird font smoothing.

Upvotes: 1

Views: 168

Answers (0)

Related Questions