https://github.com/udevbe/react-canvaskit
Experiment in creating a custom react renderer using an offscreen webgl canvas on top of Skia CanvasKit
https://github.com/udevbe/react-canvaskit
accelerated canvas canvaskit hardware-acceleration html5 html5-canvas react react-reconciler reactjs skia skia-library webgl
Last synced: 6 months ago
JSON representation
Experiment in creating a custom react renderer using an offscreen webgl canvas on top of Skia CanvasKit
- Host: GitHub
- URL: https://github.com/udevbe/react-canvaskit
- Owner: udevbe
- License: mit
- Created: 2020-04-10T10:56:22.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2022-01-10T12:35:50.000Z (over 3 years ago)
- Last Synced: 2025-03-18T13:04:25.289Z (7 months ago)
- Topics: accelerated, canvas, canvaskit, hardware-acceleration, html5, html5-canvas, react, react-reconciler, reactjs, skia, skia-library, webgl
- Language: TypeScript
- Homepage:
- Size: 14.6 MB
- Stars: 121
- Watchers: 4
- Forks: 13
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# React-CanvasKit

Experimental implementation of [Skia CanvasKit](https://skia.org/user/modules/canvaskit) using [ReactJS](https://reactjs.org/).
This implementation allows you to use all familiar React concepts like hooks and contexts, in conjunction with JXS elements that closely match the existing Skia CanvasKit API. Everything is drawn to a hardware accelerated WebGL canvas.
# Examples
#### Paragraph with dynamic font loading
```typescript jsx
import type { FunctionComponent } from 'react'
import React from 'react'
import { FontManagerProvider } from 'react-canvaskit'
import ParagraphDemo from './ParagraphDemo'const robotoPromise = fetch('https://storage.googleapis.com/skia-cdn/google-web-fonts/Roboto-Regular.ttf')
.then((resp) => resp.arrayBuffer())
const notoColorEmojiPromise = fetch('https://storage.googleapis.com/skia-cdn/misc/NotoColorEmoji.ttf')
.then((resp) => resp.arrayBuffer())const fontsPromise = Promise.all([robotoPromise, notoColorEmojiPromise])
export const App: FunctionComponent = () => {
const [fonts, setFonts] = React.useState(undefined)
fontsPromise.then(fetchedFonts => setFonts(fetchedFonts))return (
)
}
``````typescript jsx
import type { SkParagraph } from 'canvaskit-oc'
import React from 'react'
import type { SkObjectRef } from 'react-canvaskit'
import { PaintStyle, TextAlignEnum, useFontManager } from 'react-canvaskit'
import useAnimationFrame from './useAnimationFrame'const fontPaint = { style: PaintStyle.Fill, antiAlias: true }
const X = 250
const Y = 250
const paragraphText = 'The quick brown fox ๐ฆ ate a zesty hamburgerfonts ๐.\nThe ๐ฉโ๐ฉโ๐งโ๐ง laughed.'export default () => {
const skParagraphRef = React.useRef>(null)
const fontManager = useFontManager()const calcWrapTo = (time: number): number => 350 + 150 * Math.sin(time / 2000)
const [wrapTo, setWrapTo] = React.useState(calcWrapTo(performance.now()))useAnimationFrame(time => setWrapTo(calcWrapTo(time)))
return (
{paragraphText}
{`At (${X.toFixed(2)}, ${Y.toFixed(2)}) glyph is '${glyph}'`}
)
}
```#### Simple Paint
```typescript jsx
const App: FunctionComponent = () => {
return (
Hello React-CanvasKit!
React-CanvasKit.
)
}const htmlCanvasElement = document.createElement('canvas')
const rootElement = document.getElementById('root')
if (rootElement === null) {
throw new Error('No root element defined.')
}
rootElement.appendChild(htmlCanvasElement)
document.body.appendChild(htmlCanvasElement)
htmlCanvasElement.width = 400
htmlCanvasElement.height = 300init().then(() => render(, htmlCanvasElement))
```