remotion-dev/remotion























The issue has been solved
Easy to import Google Fonts using `@remotion/google-fonts` #1394
JonnyBurger posted onGitHub
š This issue is part of our Hacktoberfest campaign! š Read more about Hacktoberfest here š This issue is taken by @ayatkyo! š° Thanks to CodeChem for sponsoring this issue!
Currently it is a bit of a hassle to add Google fonts to Remotion. Here is an idea of how we can make an easy to use API:
- There is JSON information about each Google Font, for example about Roboto:
{
category: 'sans-serif',
lastModified: '2021-09-22',
subsets: [
'cyrillic',
'cyrillic-ext',
'greek',
'greek-ext',
'latin',
'latin-ext',
'vietnamese',
],
unicodeRange: {
cyrillic: 'U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116',
'cyrillic-ext':
'U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F',
greek: 'U+0370-03FF',
'greek-ext': 'U+1F00-1FFF',
latin:
'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD',
'latin-ext':
'U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF',
vietnamese:
'U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB',
},
variants: {
italic: {
'100': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOiCnqEu92Fr1Mu51QrEz4dKw.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOiCnqEu92Fr1Mu51QrEz4dKA&skey=8f53aa2e7deadc4a&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOiCnqEu92Fr1Mu51QrEz4dKg.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOiCnqEu92Fr1Mu51QrEz4dKQ.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOiCnqEu92Fr1Mu51QrEzAdLw.woff2',
},
},
'300': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TjASc0CsA.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOjCnqEu92Fr1Mu51TjASc0CsM&skey=8f644060176e1f7e&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TjASc0CsE.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TjASc0CsI.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TjASc6CsQ.woff2',
},
},
'400': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1Mu51xGIzY.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOkCnqEu92Fr1Mu51xGIzU&skey=c608c610063635f9&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1Mu51xGIzc.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1Mu51xGIzQ.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1Mu51xIIzI.woff2',
},
},
'500': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51S7ACc0CsA.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOjCnqEu92Fr1Mu51S7ACc0CsM&skey=c985e17098069ce0&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51S7ACc0CsE.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51S7ACc0CsI.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51S7ACc6CsQ.woff2',
},
},
'700': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TzBic0CsA.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOjCnqEu92Fr1Mu51TzBic0CsM&skey=dd030d266f3beccc&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TzBic0CsE.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TzBic0CsI.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2',
},
},
'900': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TLBCc0CsA.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOjCnqEu92Fr1Mu51TLBCc0CsM&skey=b80be3241fe40325&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TLBCc0CsE.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TLBCc0CsI.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOjCnqEu92Fr1Mu51TLBCc6CsQ.woff2',
},
},
},
normal: {
'100': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1MmgVxGIzY.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOkCnqEu92Fr1MmgVxGIzU&skey=5473b731ec7fc9c1&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1MmgVxGIzc.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1MmgVxGIzQ.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOkCnqEu92Fr1MmgVxIIzI.woff2',
},
},
'300': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmSU5fChc8.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOlCnqEu92Fr1MmSU5fChc_&skey=11ce8ad5f54705ca&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmSU5fChc9.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmSU5fChc-.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmSU5fBBc4.woff2',
},
},
'400': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu7GxO.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOmCnqEu92Fr1Mu7GxN&skey=a0a0114a1dcab3ac&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu7GxP.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu7GxM.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4mxK.woff2',
},
},
'500': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmEU9fChc8.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOlCnqEu92Fr1MmEU9fChc_&skey=ee881451c540fdec&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmEU9fChc9.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmEU9fChc-.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmEU9fBBc4.woff2',
},
},
'700': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfChc8.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOlCnqEu92Fr1MmWUlfChc_&skey=c06e7213f788649e&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfChc9.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfChc-.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfBBc4.woff2',
},
},
'900': {
local: [],
url: {
eot: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmYUtfChc8.eot',
svg: 'https://fonts.gstatic.com/l/font?kit=KFOlCnqEu92Fr1MmYUtfChc_&skey=934406f772f9777d&v=v29#Roboto',
ttf: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmYUtfChc9.ttf',
woff: 'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmYUtfChc-.woff',
woff2:
'https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmYUtfBBc4.woff2',
},
},
},
},
version: 'v29',
}
- The whole list of Google Fonts is 8MB. This is too big, so we need a way to only load specific fonts.
- Idea: Make a separate import statement for each font, e.g.
import {loadFont} from "@remotion/google-fonts/Roboto"
andimport {loadFont} from "@remotion/google-fonts/Montserrat"
. For that we need to code-generate a TypeScript file for each font. - If we can code-generate some TypeScript types based on the JSON...
type Variants = {
normal: {
weights: '400' | '500';
subsets: 'greek';
};
bold: {
weights: '600' | '700';
subsets: 'cyrillic' | 'cyrillic-ext';
};
};
- ...We can make an awesome autocomplete experience with it:
https://user-images.githubusercontent.com/1629785/195180349-8c84d55a-ceb5-4b7f-9171-3ca6aa3d9cf9.mov
- Using the following function signature:
const loadFont = <T extends keyof Variants>(
variant: T,
options: {
weights: Variants[T]['weights'][];
subsets: Variants[T]['subsets'][];
}
) => void
- I have implemented an example function of how a Google font could be loaded from JSON:
const loadFont = <T extends keyof Variants>(
variant: T,
options: {
weights: Variants[T]['weights'][];
subsets: Variants[T]['subsets'][];
}
) => {
options.weights.forEach((weight) => {
options.subsets.forEach((subset) => {
const handle = delayRender(
'Fetching Roboto font ' +
JSON.stringify({
variant,
weight: options.weights,
subset: options.subsets,
})
);
const fontFace = new FontFace(
'Roboto',
`url(${
data.variants[variant as unknown as keyof typeof data['variants']][
weight
].url.woff2
}) format('woff2')`,
{
weight,
style: variant,
unicodeRange: data.unicodeRange[subset],
}
);
fontFace
.load()
.then(() => {
document.fonts.add(fontFace);
continueRender(handle);
})
.catch((err) => {
console.log(err);
});
});
});
};
Task
Create a @remotion/google-fonts
package that allows to load each font with TypeScript autocompletion.
Acceptance criteria
- Should write a script that takes the JSON from https://github.com/jonathantneal/google-fonts-complete and generates a file for each font
- Developer should be able to import a single font using the
import {loadFont} from "@remotion/google-fonts/Roboto"
syntax, without importing the whole 8MB database - The font should be properly loaded, with only the styles and weights the user wants to be loaded
- Should not do additional work if the user calls the same function multiple times
- Write a new documentation page detailing how to exactly use this API, similar to API pages of other packages
- Update the Fonts page https://www.remotion.dev/docs/fonts to mention this new option.
If you have a different implementation idea, let me know!
Fund this Issue
Rewarded pull request
feat: `@remotion/google-fonts` #1446submitted byayatkyo(43)
Click to copy link
Recent activities