Converting a Google font for compatibility with ThreeJS: A beginner's guide

Is there a way to convert a downloaded Google font from TTF to JSON in order to use it with ThreeJS FontLoader / TextGeometry?

import LatoFont from '../assets/fonts/lato-bold.json'

const loader = new FontLoader();
const font = loader.parse(LatoFont);

        loader.load(font, font => {
            const textGeo = new TextGeometry("Krypton", {
                font: font,
                size: 200,
                height: 50,
                curveSegments: 12,
                bevelEnabled: false,
                bevelThickness: 0.5,
                bevelSize: 0.3,
                bevelOffset: 0,
                bevelSegments: 5,
            })

            const materials = [
                new THREE.MeshPhongMaterial({ color: 0x00ff00, flatShading: true }), // front
                new THREE.MeshPhongMaterial({ color: 0x00ff00 }) // side
            ]
            const textMesh = new THREE.Mesh(textGeo, materials);

            textGeo.computeBoundingBox();
            const centerOffset = - 0.5 * (textGeo.boundingBox.max.x - textGeo.boundingBox.min.x);

            textMesh.position.x = centerOffset;
            textMesh.position.y = 100;
            textMesh.position.z = 0;

            textMesh.rotation.x = 0;
            textMesh.rotation.y = Math.PI * 2;

            group.add(textMesh);
        })

After using an online converter, I encountered this error:

Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

UPDATE:

Even after updating my Vite config to include the static directory, I am still facing font loading issues when building the library and using it in another project.

const path = require('path')
const { defineConfig } = require('vite')

module.exports = defineConfig({
  build: {
    lib: {
      entry: path.resolve(__dirname, 'lib/main.ts'),
      name: 'logo-threejs',
      fileName: (format) => `logo-threejs.${format}.js`
    }
  },
  publicDir: './static',
  assetsInclude: ['**/*.typeface.json'],
});

Project Structure:

https://i.sstatic.net/fz0c7bX6.png

Answer №1

I assume you have thoroughly checked all troubleshooting steps such as paths, imports, font conversion, and JSON structure...

When using a popular online converter, I am receiving:

It's quite uncommon to load this font using parsing, as I rarely encounter this method. There might be a problem with that approach, but I'm not entirely sure.

Nevertheless, it's worth trying this method:

import { TextGeometry } from "https://esm.sh/three/addons/geometries/TextGeometry.js";
import { FontLoader } from "https://esm.sh/three/addons/loaders/FontLoader.js";

//…

const loader = new FontLoader();
loader.load(
    'https://esm.sh/@compai/font-lato/data/typefaces/normal-900.json',
    function (font) {
        const textGeometry = new TextGeometry("Hiii", {
            font: font,
            size: 2,
            height: 0.2,
        });
        const textMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        const textMesh = new THREE.Mesh(textGeometry, textMaterial);
        textMesh.position.set(-2, 0, 0);
        scene.add(textMesh);
    }
);

https://codepen.io/Lucas_Mas/pen/xxMoPwq

Here you can find all available fonts:

https://github.com/components-ai/typefaces/tree/main/packages

UPDATE 0

If I were to guess, the issue might be related to the location of the font in your directory structure. If you followed my example and either downloaded the font in JSON format or converted it using , then the problem might be with the location. I personally use Vite as my bundler.

threejs-vite-project/
├── node_modules/
├── src/
│   ├── index.html
│   ├── app.js
│   └── style.css
├── static/
│   └── font/
│       └── latoSans.json
├── package-lock.json
├── package.json
└── vite.config.js

Double-check that your vite.config.js (if you are using Vite) is configured properly to serve the static directory.

import { defineConfig } from 'vite';

export default defineConfig({
  root: 'src',
  build: {
    outDir: '../dist'
  },
  publicDir: '../static'
});

Ensure that the path in your loader looks like this:

const loader = new FontLoader();
loader.load(
  '/static/font/latoSans.json',
  function (font) {
    const textGeometry = new TextGeometry("Hiii", {
      font: font,
      size: 2,
      height: 0.2,
    });

Update your imports to look like this:

import { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';

UPDATE 1

  1. Make sure the font file has the correct extension .typeface.json - especially if you downloaded it from the link provided. fonts from that source do not have this extension by default.
  2. If you kept the default font name, consider changing it to assetsInclude: ['**/*.json']
  3. Verify the path of publicDir, paying close attention to the path structure
  4. Double-check your imports, especially the export - as you have successfully imported the font previously.

UPDATE 2

Consider trying this alternative approach:

Project A1

Project A2

Font existing...

Make sure the folders contain the necessary font files, as this is a common issue with Vite where static files may need to be moved manually.

Path Project A2

const loader = new FontLoader();
loader.load('/public/lato-bold.json', ...

Absolute path

If previous steps did not resolve the issue, try using an absolute path starting from the public directory

const aPath = '/lato-bold.json';
const loader = new FontLoader();
loader.load(aPath, ...

UPDATE 3

I don't believe that the issue lies with ts, but rather with the font loading process in general. However, it might be worth trying to set

"resolveJsonModule": true
as it is disabled by default.

Additionally, check the network requests in the devtools and any console messages for clues.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Problem uploading files with ajax in Laravel version 6

I am encountering an issue while attempting to save a PDF file along with other input values using Ajax in Laravel 6 without utilizing the form HTML element. The error message "Call to a member function getClientOriginalExtension() on null" keeps popping u ...

Tips for displaying autocomplete suggestions as clickable links?

I am new to using Ajax and trying to figure out how to display autocomplete results as clickable links. I have managed to list the related results, but I am struggling to add the links. I believe the links need to be added within the script as an HTML tag. ...

How can you effectively demonstrate that an HTML element is currently being loaded using AJAX?

At times, my application faces the issue of numerous elements loading simultaneously. To address this, I aim to display a customary AJAX spinner above the control (or DOM node) while it remains disabled. What would be the most convenient and effective app ...

The jQuery function for AJAX does not properly validate the boolean value provided by the controller

I have a controller action that returns a boolean result to jQuery. [HttpGet] public ActionResult IsVoucherValid(string voucherCode) { bool result = false; var voucher = new VoucherCode(voucherCode); if(voucher.Status==0) ...

The controller persists in its loop as it utilizes $state.go

As a newcomer to Angular, I am uncertain if this is the most effective solution. Within my state/route, there is a button that triggers the following function when clicked: _this.foo = function () { save(); $state.go("next"); } The issue arises w ...

Error in NodeJS: 'Cannot alter headers once they have been sent.'

My project involves developing an app with Express that fetches tweets from Twitter. Each API call retrieves 200 tweets (or fewer if there are less than 200) and in total, I need to retrieve 1800 tweets. To achieve this, I use a time interval to make multi ...

What is the best way to make three divs that can be adjusted in size?

Desired Layout: | A | | B | | C | ^ ^ Adjustment Behavior: | A | | B | | C | Current Issue: | A | C | I attempted to enhance the functionality by modifying the provided JavaScript cod ...

Is it possible to dynamically change the color of a box shadow using an event handler?

I'm currently in the process of developing an application that consists of six distinct topics organized within a flexbox structure, complete with a box-shadow effect. My objective is to dynamically alter the color of the box-shadow through an event ...

react-router-redux is unable to navigate to a different URL

I'm working on redirecting within a redux action when an error occurs. I attempted to utilize react-router-redux but encountered the following error. Uncaught TypeError: Cannot read property 'push' of undefined at middleware.js:29 a ...

Stopping a Bootstrap Modal Closure When Validation Errors are Present

I'm dealing with a bootstrap model within a .NET MVC5 app. Although my client-side validation is functioning properly (using jquery unobtrusive in MVC), I have encountered an issue where the modal keeps closing even when there are errors present. How ...

The functionality of my LinkButton activates a code sequence only when clicked twice during its Click event

Protected Sub lnkContractors_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkContractors.Click If Context.User.IsInRole("HOD") Then lnkContractors.OnClientClick = "PopupCenter('Juniors.aspx', &apo ...

Tips for making a multiselect dropdown menu using bootstrap

I am working on a JavaScript application that parses data and displays it to users in a table generated by JavaScript. I am looking for a simple way to allow users to choose which fields to display in the table using a dropdown list or something similar. I ...

Transparent objects can obscure other transparent items, as alphaTest does not function properly and setting depthWrite to false can lead to issues

I'm currently facing an issue with transparency. In the images provided, non-transparent objects behind a transparent object are visible. However, the backside of the other transparent object is not shown even though I've set material.side = THRE ...

The intricacies of how Node.js handles asynchronous execution flow

I wanted to ask about the best approach for displaying data retrieved from MySQL. Do you think this workflow is correct? app.get('/demo/:id', function(req, res) { var query = csql.query('SELECT * FROM table_videos WHERE id=? LIMIT 1' ...

ng-bind-html is functional, yet it is raising a TypeError

Below is the code snippet containing the ng-bind-html: <span ng-bind-html="text"></span> Here is the stack trace: angular.js:13236 TypeError: bindings.push is not a function at Function.$$addBindingInfo (http://localhost:9000/bower_component ...

"Enhance Your Website with jQuery Mobile's Multi-Page Setup and Panel

I am currently facing the challenge of managing multiple pages within a single document and I would like to utilize jQM 1.3's Panel widget to control navigation between these pages. However, the issue arises from the requirement that Panels must be co ...

Echarts: Implementing a Custom Function Triggered by Title Click Event

I recently created a bar graph using Echart JS, but I'm struggling to customize the click event on the title bar. I attempted to use triggerEvent, but it only seems to work on statistics rather than the title itself. JSFiddle var myChart = echarts.i ...

Instantiate a fresh Date object in JavaScript by passing in my specific parameter

Check out this code snippet: $(function () { var timestamp = 1443563590; //Tue, 29 Sep 2015 21:53:10 GMT var today2 = moment.unix(timestamp).tz('America/New_York').toString(); alert(today2); //var dateinNewYork = new Date(wh ...

New Angular Datatables used to create a revitalizing table

In my project, I am utilizing the Angular Datatables library. The data is fetched from a URL that returns a JSON object, which is then stored in an array and used to populate a table. appenditems(){ this.items = []; this.items2 = []; this.items ...

There seems to be an issue with a potentially null object in an Angular project while trying to view a PDF file

IDENTIFY THE ERROR: printContents = document.getElementById('print').innerHTML.toString(); ON LINE 4: print(): void { let printContents!: string; let popupWin!: any; printContents = document.getElementById('print').innerHTM ...