{"id":489,"date":"2026-10-20T14:31:32","date_gmt":"2026-10-20T06:31:32","guid":{"rendered":"https:\/\/en.meishesdk.com\/blog\/?p=489"},"modified":"2026-10-20T14:31:33","modified_gmt":"2026-10-20T06:31:33","slug":"built-an-open-source-react-face-filters-sdk","status":"publish","type":"post","link":"https:\/\/en.meishesdk.com\/blog\/489.html","title":{"rendered":"Built an open-source React Face Filters SDK"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Let us start by being precise about the word in that title, because for a&nbsp;<strong>React Face Filters SDK<\/strong>&nbsp;it is the word most likely to mislead.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What we publish alongside the SDK is&nbsp;<strong>companion source code<\/strong>: a reference React integration layer, structured to be productized rather than read once and abandoned. It is not a rewrite of the engine, it is not a distributable package pulled from a registry, and it carries no named licence of its own. It is production-ready demo source code, written so that a team can read it once and then run it as a starting point for their own product rather than as a sample to be admired and discarded.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The engine itself is a commercial product. Everything below is about the layer above it, which is where your team will spend most of its time anyway.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Product Positioning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Meishe Face Filters SDK is the filter and effects layer of the Face AR SDK family. It evaluates real-time effects without pre-processing on the cross-platform audio\/video processing engine used across the product family, serving capture, timeline editing, and live streaming from one stack.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Content ships as data: individual elements and complete looks, with per-element intensity control, delivered as packages that update without a new binary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The SDK ships no finished camera UI, and the companion source is where that absence is answered \u2014 with real recording screens, permission flows, and look browsing you can take ownership of rather than reverse-engineer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. What is published, and what is not<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The distinction is worth stating as a list, because most confusion comes from collapsing two things into one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Published.<\/strong>&nbsp;A reference React integration layer: how a screen mounts the native preview, how commands are sent downward, how readiness and failure states are modelled, and how the look catalog is rendered from data. It is written to be read and then owned.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Not published.<\/strong>&nbsp;The rendering core, detection and tracking implementations, and the evaluation pipeline. These are the commercial product, and no amount of companion source changes that boundary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Not applicable.<\/strong>&nbsp;There is no licence grant over the engine, and no separate licence covering the companion layer. You receive it as part of working with the product, not as an independently licensed artefact.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That third point matters more than it sounds. Teams sometimes plan around redistributing the sample layer inside their own product as though it carried independent terms; it does not, and this is worth confirming during your evaluation rather than discovering later.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/en.meishesdk.com\/blog\/wp-content\/uploads\/2026\/10\/2026102006305782.png\" alt=\"Built an open-source React Face Filters SDK\" title=\"Built an open-source React Face Filters SDK\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"572\" src=\"https:\/\/en.meishesdk.com\/blog\/wp-content\/uploads\/2026\/10\/2026102006305782-1024x572.png\" alt=\"Built an open-source React Face Filters SDK\" alt=\"\" class=\"wp-image-490\" srcset=\"https:\/\/en.meishesdk.com\/blog\/wp-content\/uploads\/2026\/10\/2026102006305782-1024x572.png 1024w, https:\/\/en.meishesdk.com\/blog\/wp-content\/uploads\/2026\/10\/2026102006305782-300x167.png 300w, https:\/\/en.meishesdk.com\/blog\/wp-content\/uploads\/2026\/10\/2026102006305782-768x429.png 768w, https:\/\/en.meishesdk.com\/blog\/wp-content\/uploads\/2026\/10\/2026102006305782.png 1254w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">3. Inside the reference layer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The layer is organised around one idea:&nbsp;<strong>the interface your users touch belongs in React, and everything per-frame belongs below it.<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">The snippet below is schematic. Structure is illustrative; file names and props are not the shipped surface.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Illustrative shape of a companion integration layer, using relative paths.\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { EffectPreview } from \".\/native\/EffectPreview\";      \/\/ native view wrapper\nimport { LookCatalog } from \".\/components\/LookCatalog\";      \/\/ declarative UI\nimport { useLookManifest } from \".\/state\/useLookManifest\";   \/\/ your data, your cadence\n\nexport function CaptureStack() {\n  const preview = useRef&lt;EffectPreview&gt;(null);\n  const manifest = useLookManifest();\n  const &#91;active, setActive] = useState&lt;string | null&gt;(null);\n\n  const catalog = useMemo(() =&gt; manifest.groupedBySeries(), &#91;manifest]);\n\n  useEffect(() =&gt; {\n    if (active) void preview.current?.apply(active); \/\/ one coarse command down\n  }, &#91;active]);\n\n  return (\n    &lt;&gt;\n      &lt;EffectPreview ref={preview} style={{ flex: 1 }} \/&gt;\n      &lt;LookCatalog groups={catalog} onSelect={setActive} \/&gt;\n    &lt;\/&gt;\n  );\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Read it against the Product Positioning above and the structure explains itself.&nbsp;<code>LookCatalog<\/code>&nbsp;is ordinary React rendering from data.&nbsp;<code>EffectPreview<\/code>&nbsp;wraps a native view that owns the camera and the loop. State flows downward as a look identifier, and nothing per-frame flows upward.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alongside the source itself, support follows the same modular pattern as the SDK: 1V1 assistance during integration, plus downloadable Integration Skills for AI coding assistants including Codex, Qoder, Claude Code and Cursor, which lets the assistant you already use read your own copy rather than guess at it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Taking ownership rather than reading once<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The companion source is deliberately incomplete in one specific way: it solves the integration, and it leaves your product decisions to you.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Part of the layer<\/th><th class=\"has-text-align-left\" data-align=\"left\">Adopt as-is<\/th><th class=\"has-text-align-left\" data-align=\"left\">Expect to replace<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-left\" data-align=\"left\">Preview mounting and lifecycle<\/td><td class=\"has-text-align-left\" data-align=\"left\">Yes<\/td><td class=\"has-text-align-left\" data-align=\"left\">Rarely<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\">Command boundary (look, level, record)<\/td><td class=\"has-text-align-left\" data-align=\"left\">Yes<\/td><td class=\"has-text-align-left\" data-align=\"left\">Only if you need new verbs<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\">Readiness and failure states<\/td><td class=\"has-text-align-left\" data-align=\"left\">Yes<\/td><td class=\"has-text-align-left\" data-align=\"left\">Adjust copy and fallback UI<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\">Catalog rendering from manifest<\/td><td class=\"has-text-align-left\" data-align=\"left\">Partly<\/td><td class=\"has-text-align-left\" data-align=\"left\">Your information architecture differs<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\">Navigation and product chrome<\/td><td class=\"has-text-align-left\" data-align=\"left\">No<\/td><td class=\"has-text-align-left\" data-align=\"left\">Always<\/td><\/tr><tr><td class=\"has-text-align-left\" data-align=\"left\">Upload and sharing flow<\/td><td class=\"has-text-align-left\" data-align=\"left\">No<\/td><td class=\"has-text-align-left\" data-align=\"left\">Always yours<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Teams get into trouble when they treat the sample&#8217;s product decisions as recommendations. The source shows a working boundary, not a recommended information architecture; the parts marked &#8220;replace&#8221; above are where your own opinions belong.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Where the boundary sits in code<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Three rules keep the layer honest as it grows.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Commands downward, status upward.<\/strong>&nbsp;A look identifier or an intensity level is a command. Nothing pixels-shaped crosses into JavaScript, and anything that changes every frame stays below React.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>A look is a reference, not a file.<\/strong>&nbsp;The companion layer reads identifiers and lets the engine resolve element packages. Your code should never need to know how many elements a look contains.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Failure is a state, not an exception.<\/strong>&nbsp;Preview unavailable, package unresolved, permission denied \u2014 each renders something specific. The demo models these because production apps must.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">The snippet below is schematic. Names are illustrative and are not the shipped API surface.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Illustrative failure-aware apply flow.\ntype ApplyState = \"idle\" | \"resolving\" | \"ready\" | \"unavailable\";\n\nexport function useApplyLook(preview: RefObject&lt;EffectPreview&gt;, lookId: string | null) {\n  const &#91;state, setState] = useState&lt;ApplyState&gt;(\"idle\");\n\n  useEffect(() =&gt; {\n    if (!lookId) return;\n    let cancelled = false;\n    (async () =&gt; {\n      setState(\"resolving\");\n      try {\n        await preview.current?.resolve(lookId);\n        await preview.current?.apply(lookId);\n        if (!cancelled) setState(\"ready\");\n      } catch {\n        if (!cancelled) setState(\"unavailable\"); \/\/ render a fallback, never black\n      }\n    })();\n    return () =&gt; { cancelled = true; };\n  }, &#91;preview, lookId]);\n\n  return state;\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. Running it against your own library<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The fastest useful evaluation is to put your own content through it rather than reviewing it empty.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Take ten looks drawing on twenty shared elements, including two you intend to retire. Apply each through the reference screens, step elements through light, standard, and strong while recording, and then \u2014 the step most skip \u2014 change one shared element and confirm every look referencing it reflects the change without individual re-export.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then break something deliberately. Withdraw a package, apply a look while another is resolving, background the app mid-recording. The value of reading source is knowing what it does under those conditions before your users find them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. What no amount of source access changes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Three limits are properties of the medium, not of access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Compression sets one ceiling. Many captures arrive from low-resolution, heavily compressed front cameras, and fine detail degrades first around the eyes and along the lip line. Reading source will not reveal a fix, because the information was discarded before the frame arrived.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lighting sets another. Rendered pigment lands inside the exposure and white balance of each frame, so the same shade reads differently in daylight, indoors, and under mixed sources; the render follows the picture rather than correcting the room. Access to more code does not change that relation, and interfaces should say that what users see is a preview, not a colour measurement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And the native boundary is not optional. Frames belong below React whatever the layer above looks like. The companion source demonstrates that boundary; it does not offer a way around it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Is the SDK engine itself published as open source?<\/strong><br>No. The core is a commercial product. What ships alongside it is production-ready demo source code \u2014 a reference React integration layer you can read, extend, and run inside your own application \u2014 rather than the rendering engine, the detection code, or the evaluation pipeline.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Can we redistribute the companion layer with our product?<\/strong><br>It is not an independently licensed artefact, so treat redistribution as something to confirm rather than assume. The layer exists so you can own your integration, not so that it becomes a dependency you ship onward.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Do we need it, or can we write the integration from scratch?<\/strong><br>Plenty of teams do write from scratch, particularly those with an existing native camera stack. Its value is showing the working boundary \u2014 mounting, lifecycle, readiness states, failure branches \u2014 before you discover those requirements yourself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Will reading it help us support an unusual device behaviour?<\/strong><br>Partly. It will show how pipeline lifecycle and failure are modelled, which is where most device-specific behaviour surfaces. Device-level quirks themselves still require testing on the hardware involved.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What happens when the engine changes?<\/strong><br>Because the layer communicates through coarse commands, surface changes at the engine level usually touch the wrapper rather than your screens. Keeping that boundary narrow is why reviewing demo source is worth the hour.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ready to see it in your own stack?&nbsp;<a href=\"https:\/\/en.meishesdk.com\/register\" target=\"_blank\" rel=\"noreferrer noopener\" rel=\"nofollow\" >Request a free trial<\/a>&nbsp;or&nbsp;<a href=\"https:\/\/en.meishesdk.com\/\" target=\"_blank\" rel=\"noreferrer noopener\" rel=\"nofollow\" >talk to our integration team<\/a>&nbsp;\u2014 we&#8217;ll help you scope the modules you actually need.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let us start by being precise about the word in that title, because for a&nbsp;React Face Filters SDK&nbsp;it is the word most likely to mislead. What we publish alongside the SDK is&nbsp;companion source code: a reference React integration layer, structured to be productized rather than read once and abandoned. It is not a rewrite of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":490,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[36,386,372],"class_list":["post-489","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-face-ar-sdk","tag-effects-filter-sdk","tag-face-filters-sdk","tag-open-source"],"_links":{"self":[{"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/posts\/489","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/comments?post=489"}],"version-history":[{"count":1,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/posts\/489\/revisions"}],"predecessor-version":[{"id":491,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/posts\/489\/revisions\/491"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/media\/490"}],"wp:attachment":[{"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/media?parent=489"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/categories?post=489"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/en.meishesdk.com\/blog\/wp-json\/wp\/v2\/tags?post=489"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}