diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..28bbb76 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,42 @@ +name: Deploy + +env: + NODE_VERSION: 17 + ZOLA_VERSION: 0.16.1 + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Install Zola + run: | + set -x + wget -O - \ + "https://github.com/getzola/zola/releases/download/v${ZOLA_VERSION}/zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \ + | sudo tar xzf - -C /usr/local/bin + + - name: Install dependencies + run: npm install + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitmodules b/.gitmodules index 256a87b..a47d3d7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,5 @@ [submodule "etro"] path = etro url = https://github.com/etro-js/etro.git +[submodule "etro/"] + url = https://github.com/etro-js/etro.git diff --git a/content/_index.md b/content/_index.md index 56ecefe..26b2d74 100644 --- a/content/_index.md +++ b/content/_index.md @@ -19,13 +19,9 @@ npm install etro # Usage -Include it with ```js - -``` +import etro from 'etro' -Let's look at an example: -```js var movie = new etro.Movie({ canvas: outputCanvas }) var layer = new etro.layer.Video({ startTime: 0, source: videoElement }) // the layer starts at 0s movie.addLayer(layer) diff --git a/content/docs.md b/content/docs.md index c7dac99..90b6701 100644 --- a/content/docs.md +++ b/content/docs.md @@ -6,7 +6,12 @@ weight = 0
Documentation
- -- [Tutorial](tutorial) -- [Migrating to v0.8.0](migrating-v0-8-0) -- [API Reference](api) +Welcome to the Etro documentation! + +- To learn the fundamentals of Etro, check out the [reference](reference) +section +- To use Etro in a React app, check out the [Webcam +Filter](guides/webcam-filter) guide +- The full API documentation can be found [here](api) +- To learn how to migrate from Etro v0.7 to v0.8, check out the [migration +guide](migrating-v0-8-0) diff --git a/content/docs/guides/webcam-filter.md b/content/docs/guides/webcam-filter.md new file mode 100644 index 0000000..6cc10ab --- /dev/null +++ b/content/docs/guides/webcam-filter.md @@ -0,0 +1,276 @@ ++++ +title = "Webcam Filter" +template = "page.html" ++++ + +
Webcam Filter
+ +In this guide, we'll create a simple webcam filter using React and Etro. + +## Setting up the React app + +First, we'll set up a new React app using +[create-react-app](https://create-react-app.dev): + +```bash +npx create-react-app webcam-filter +cd webcam-filter +``` + +## Installing Etro + +Now, we'll install Etro: + +```bash +npm install etro +``` + +## Creating the movie + +Now, we'll create a new movie, add a webcam layer to it, and play it. + +Create a new file `src/Movie.js`: + +```js +import React, { useEffect, useRef } from "react"; +import etro from "etro"; + +export default function Movie() { + const canvasRef = useRef(); + const movieRef = useRef(); + + useEffect(() => { + // Use the canvas ref to get the canvas element + const canvas = canvasRef.current; + + // Create a new movie instance + const movie = new etro.Movie({ canvas }); + + // Get the user's webcam stream + navigator.mediaDevices + .getUserMedia({ video: true }) + + // Create a video element from the stream + .then((stream) => { + const video = document.createElement("video"); + video.srcObject = stream; + return new Promise((resolve) => { + video.onloadedmetadata = () => { + resolve(video); + }; + }); + }) + + // Add a video layer to the movie and play it + .then((video) => { + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + const layer = new etro.layer.Video({ + startTime: 0, + source: video, + }); + movie.addLayer(layer); + movie.play(); + movieRef.current = movie; + }); + }, []); + + return ; +} +``` + +Use the `Movie` component in `src/App.js`: + +```js +import React from 'react' +import Movie from './Movie' + +function App() { + return ( +
+ +
+ ) +} +``` + +## Adding an effect + +Now, we'll add an effect to the webcam layer. + +Create a new file `src/effect.js`: + +```js +import etro from "etro"; + +export default class SaturationEffect extends etro.effect.Shader { + constructor(options = {}) { + super({ + fragmentSource: ` + precision highp float; + + uniform sampler2D u_Source; + uniform float u_Saturation; + + varying vec2 v_TextureCoord; + + void main() { + vec4 color = texture2D(u_Source, v_TextureCoord); + float luminance = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); + gl_FragColor = vec4(mix(vec3(luminance), color.rgb, u_Saturation), color.a); + } + `, + uniforms: { + saturation: "1f", + }, + }); + + this.saturation = options.saturation || 1; + } +} +``` + +Next we need to add the effect to the layer. We'll do this in `src/Movie.js`. + +Import the effect: + +```diff + import React, { useEffect, useRef } from "react"; + import etro from "etro"; ++import SaturationEffect from "./effect"; +``` + +Add a `saturation` property to the `Movie` component: + +```diff +-export default function Movie() { ++export default function Movie({ saturation = 1 }) { +``` + +Create a ref to store the effect instance: + +```diff + export default function Movie() { + const canvasRef = useRef(); + const movieRef = useRef(); ++ const effectRef = useRef(); +``` + +Add the effect to the layer: + +```diff + const layer = new etro.layer.Video({ + startTime: 0, + source: video, + }); ++ const effect = new SaturationEffect(); ++ layer.addEffect(effect); ++ + movie.addLayer(layer); + movie.play(); + movieRef.current = movie; ++ effectRef.current = effect; + }); +``` + +Now, update the effect when the `saturation` prop changes: + +```diff + movie.play(); + + effectRef.current = effect; + movieRef.current = movie; + }); + }, []); ++ ++ useEffect(() => { ++ if (effectRef.current) { ++ effectRef.current.saturation = saturation; ++ } ++ }, [saturation]); +``` + +Finally, we can pass a temporary `saturation` value to the `Movie` component in +`src/App.js`: + +```diff + import React from 'react' + import Movie from './Movie' + + function App() { + return ( +
+- ++ +
+ ) + } +``` + +## Changing the saturation + +Now, we'll add a slider to change the saturation. + +Create a new file `src/Slider.js`: + +```js +import React from "react"; + +export default function Slider({ value, onChange }) { + return ( + onChange(e.target.value)} + /> + ); +} +``` + +Now, import the slider in `src/App.js`: + +```diff + import React from 'react' + import Movie from './Movie' ++import Slider from './Slider' + + function App() { + return ( +
+ ++ +
+ ) + } +``` + +Next, we'll add a state variable to the app to store the saturation value. This +value will be modified by the slider and passed to the effect: + +```diff + import React from 'react' + import Movie from './Movie' + import Slider from './Slider' + + function App() { ++ const [saturation, setSaturation] = React.useState(1) ++ + return ( +
+- +- ++ ++ +
+ ) + } +``` + +## Conclusion + +That's it! You've created a webcam app with a saturation effect. If you have +any questions, feel free to ask them in the [etro Discord +server](https://discord.gg/myrBsQ8Cht). diff --git a/content/docs/reference.md b/content/docs/reference.md new file mode 100644 index 0000000..89646aa --- /dev/null +++ b/content/docs/reference.md @@ -0,0 +1,13 @@ ++++ +title = "Reference" +template = "page.html" ++++ + +
Reference
+ +\+ [Framework Overview](overview)
+\+ [Movies](movies)
+\+ [Layers](layers)
+\+ [Effects](effects)
+\+ [Dynamic Properties](dynamic-properties)
+\+ [Property Filters](property-filters)
diff --git a/content/docs/tutorial/dynamic-properties.md b/content/docs/reference/dynamic-properties.md similarity index 100% rename from content/docs/tutorial/dynamic-properties.md rename to content/docs/reference/dynamic-properties.md diff --git a/content/docs/tutorial/effects.md b/content/docs/reference/effects.md similarity index 100% rename from content/docs/tutorial/effects.md rename to content/docs/reference/effects.md diff --git a/content/docs/tutorial/layers.md b/content/docs/reference/layers.md similarity index 100% rename from content/docs/tutorial/layers.md rename to content/docs/reference/layers.md diff --git a/content/docs/tutorial/movies.md b/content/docs/reference/movies.md similarity index 89% rename from content/docs/tutorial/movies.md rename to content/docs/reference/movies.md index 1a22ffd..7a1b913 100644 --- a/content/docs/tutorial/movies.md +++ b/content/docs/reference/movies.md @@ -23,4 +23,5 @@ movie.height = 200 // also sets the canvas's height to 200 ``` Now we have a 200x200 movie, but there are no layers so nothing will be -rendered. In the [next section](layers), we'll add a video clip to the movie. +rendered. In the [next section](../layers), we'll add a video clip to the +movie. diff --git a/content/docs/tutorial/overview.md b/content/docs/reference/overview.md similarity index 87% rename from content/docs/tutorial/overview.md rename to content/docs/reference/overview.md index ee9f625..012a229 100644 --- a/content/docs/tutorial/overview.md +++ b/content/docs/reference/overview.md @@ -25,7 +25,7 @@ movie.play() movie.record({ frameRate: 30 }).then(blob => /*do something with `blob`*/) ``` -See the [`Movie` documentation](./movies.md). +See the [`Movie` documentation](../movies.md). # Layers @@ -39,15 +39,15 @@ var layer2 = new etro.layer.Video({ startTime: 3, source: htmlVideoEl }) movie.layers.push(layer1, layer2) // the same as calling movie.addLayer ``` -There are a number of [built-in layers](../api/modules/layer.html), but you can -also subclass any of them and create your own. +There are a number of [built-in layers](/docs/api/modules/layer.html), but you +can also subclass any of them and create your own. # Effects Effects alter a layer or movie's output. Currently, only visual effects are supported. Audio can be manipulated using the [web audio API] (see -[`Audio`](../api/classes/layer.audio.html)). Etro offers a set of [built-in -effects](../api/modules/effect.html) that can be used like this: +[`Audio`](/docs/api/classes/layer.audio.html)). Etro offers a set of [built-in +effects](/docs/api/modules/effect.html) that can be used like this: ```js var effect = new etro.effect.Contrast(2.0) layer.addEffect(effect) diff --git a/content/docs/tutorial/property-filters.md b/content/docs/reference/property-filters.md similarity index 100% rename from content/docs/tutorial/property-filters.md rename to content/docs/reference/property-filters.md diff --git a/content/docs/tutorial.md b/content/docs/tutorial.md deleted file mode 100644 index fa5b699..0000000 --- a/content/docs/tutorial.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Tutorial" -template = "page.html" -+++ - -
Tutorial
- -1. [Framework Overview](overview) -2. [Movies](movies) -3. [Layers](layers) -4. [Effects](effects) -5. [Dynamic Properties](dynamic-properties) -6. [Property Filters](property-filters) diff --git a/etro b/etro index 2a0b559..487f206 160000 --- a/etro +++ b/etro @@ -1 +1 @@ -Subproject commit 2a0b559d896cdc7fa5beb391a1239abc65a2f268 +Subproject commit 487f206ff139a2ae462b01d10c0077980d00795d diff --git a/package.json b/package.json index c59b1e5..d191701 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,10 @@ "description": "", "main": "index.js", "scripts": { + "reset": "git submodule deinit -f --all && git submodule update --init --recursive", "start": "zola serve", "test": "echo \"Error: no test specified\" && exit 1", - "build": "rm -r public; zola build && cp CNAME public && cd etro && npm i && npm run doc && mv docs ../public/docs/api && git restore package-lock.json", + "build": "npm run reset && rm -rf public; zola build && cp CNAME public && cd etro && npm i && npm run doc && mv docs ../public/docs/api && git restore package-lock.json", "prepublish": "npm run build", "publish": "gh-pages -d public" }, diff --git a/sass/style.sass b/sass/style.sass index bca3462..8d4efa1 100644 --- a/sass/style.sass +++ b/sass/style.sass @@ -13,12 +13,3 @@ pre code font-weight: bold font-family: "Fira Sans", sans-serif !important -body - min-height: 100vh - -main - min-height: 66vh - padding-top: -50em - -.content - justify-content: normal diff --git a/templates/index.html b/templates/index.html index 3c3d1c4..8cca3fa 100644 --- a/templates/index.html +++ b/templates/index.html @@ -17,7 +17,7 @@

Star - Fork
@@ -69,12 +69,9 @@

{% endif %} {% endblock toc %} {% block footer %} -