├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── BUG-REPORT.yml │ └── FEATURE-REQUEST.yml └── workflows │ ├── examples.yml │ ├── inactive.yaml │ └── tests.yml ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode ├── extensions.json └── settings.json ├── BROWSERS.md ├── CONTRIBUTING.md ├── COPYING ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── RELEASE.md ├── docs ├── CustomShaderEffectTexture.md ├── ManualRegressionTests.md ├── NodeDependencyGraph.md ├── example-projects │ └── custom-shader-effect-texture │ │ ├── index.html │ │ ├── package.json │ │ ├── pnpm-lock.yaml │ │ ├── pnpm-workspace.yaml │ │ ├── src │ │ ├── MyCustomShader.ts │ │ ├── MyCustomTexture.ts │ │ ├── assets │ │ │ └── robot.png │ │ ├── index.ts │ │ └── vite-env.d.ts │ │ ├── tsconfig.cfg.json │ │ ├── tsconfig.json │ │ └── vite.config.ts └── images │ ├── dependency-graph.png │ └── dependency-graph.txt ├── eslint.config.js ├── examples ├── .npmrc ├── README.md ├── assets │ ├── elevator.png │ ├── elevator.svg │ ├── green-100.png │ ├── green-25.png │ ├── green-50.png │ ├── green-50.psd │ ├── lightning.png │ ├── lightning.svg │ ├── red-100.png │ ├── red-25.png │ ├── red-50.png │ ├── robot │ │ ├── elevator-background.png │ │ ├── elevator-door-bottom-top-floor.png │ │ ├── elevator-door-left-ground-floor.png │ │ ├── elevator-door-right-ground-floor.png │ │ ├── elevator-door-shadow-ground-floor.png │ │ ├── elevator-door-top-top-floor.png │ │ ├── environment.png │ │ ├── robot-shadow.png │ │ └── robot.png │ ├── rocko.png │ ├── rocko.svg │ ├── rocko2.svg │ ├── spritemap.png │ ├── test-etc1.pvr │ ├── test-s3tc.ktx │ ├── testscreen.png │ ├── testscreen.svg │ └── testscreen_rotated.png ├── common │ ├── Character.ts │ ├── Component.ts │ ├── ExampleSettings.ts │ ├── LocalStorage.ts │ ├── LoremIpsum.ts │ ├── MemMonitor.ts │ ├── PageContainer.ts │ ├── StatTracker.ts │ ├── constructTestRow.ts │ ├── installFonts.ts │ ├── installShaders.ts │ ├── paginateTestRows.ts │ ├── setupMathRandom.ts │ └── utils.ts ├── index.html ├── index.ts ├── package.json ├── public │ └── fonts │ │ ├── NotoSans-Bold.ttf │ │ ├── NotoSans-Regular.ssdf.json │ │ ├── NotoSans-Regular.ssdf.png │ │ ├── NotoSans-Regular.ttf │ │ ├── Ubuntu-Bold.msdf.json │ │ ├── Ubuntu-Bold.msdf.png │ │ ├── Ubuntu-Bold.ssdf.json │ │ ├── Ubuntu-Bold.ssdf.png │ │ ├── Ubuntu-Bold.ttf │ │ ├── Ubuntu-Regular.msdf.json │ │ ├── Ubuntu-Regular.msdf.png │ │ ├── Ubuntu-Regular.ssdf.json │ │ ├── Ubuntu-Regular.ssdf.png │ │ └── Ubuntu-Regular.ttf ├── tests │ ├── absolute-position.ts │ ├── alignment.ts │ ├── alpha-blending.ts │ ├── alpha.ts │ ├── animation-events.ts │ ├── animation.ts │ ├── child-positioning.ts │ ├── clear-color-setting.ts │ ├── clipping-mutations.ts │ ├── clipping.ts │ ├── destroy.ts │ ├── detect-touch.ts │ ├── gradient.ts │ ├── inspector.ts │ ├── mount-pivot.ts │ ├── no-rtt.ts │ ├── quads-rendered.ts │ ├── render-bounds.ts │ ├── render-settings.ts │ ├── resize-mode.ts │ ├── robot.ts │ ├── rotation.ts │ ├── rtt-dimension.ts │ ├── rtt-nested-clipping.ts │ ├── rtt-reflection.ts │ ├── rtt-spritemap.ts │ ├── rtt.ts │ ├── scaling-animations.ts │ ├── scaling.ts │ ├── shader-animation.ts │ ├── shader-border.ts │ ├── shader-hole-punch.ts │ ├── shader-linear-gradient.ts │ ├── shader-radial-gradient.ts │ ├── shader-rounded.ts │ ├── shader-shadow.ts │ ├── stress-images.ts │ ├── stress-mix.ts │ ├── stress-multi-level-bounds.ts │ ├── stress-multi-level-clipping.ts │ ├── stress-multi-level.ts │ ├── stress-multi-texture.ts │ ├── stress-single-level-text.ts │ ├── stress-single-level.ts │ ├── stress-textures.ts │ ├── test.ts │ ├── text-align.ts │ ├── text-alpha.ts │ ├── text-baseline.ts │ ├── text-canvas-font-no-metrics.ts │ ├── text-canvas.ts │ ├── text-contain.ts │ ├── text-dimensions.ts │ ├── text-events.ts │ ├── text-layout-consistency-modified-metrics.ts │ ├── text-layout-consistency.ts │ ├── text-line-height.ts │ ├── text-max-lines.ts │ ├── text-mixed.ts │ ├── text-offscreen-move.ts │ ├── text-overflow-suffix.ts │ ├── text-rotation.ts │ ├── text-scaling.ts │ ├── text-ssdf.ts │ ├── text-vertical-align.ts │ ├── text-wordbreak.ts │ ├── text-zwsp.ts │ ├── text.ts │ ├── texture-autosize.ts │ ├── texture-base64.ts │ ├── texture-cleanup-critical.ts │ ├── texture-cleanup-idle.ts │ ├── texture-factory.ts │ ├── texture-memory-allocation.ts │ ├── texture-memory-rtt.ts │ ├── texture-memory-spritemap.ts │ ├── texture-reload.ts │ ├── texture-source.ts │ ├── texture-spritemap.ts │ ├── texture-svg.ts │ ├── textures.ts │ ├── tx-compression.ts │ ├── viewport-boundsmargin.ts │ ├── viewport-events-canvas.ts │ ├── viewport-events.ts │ ├── viewport-largebound.ts │ ├── viewport-memory.ts │ ├── viewport-strictbounds.ts │ └── zIndex.ts ├── tsconfig.json ├── vite-env.d.ts └── vite.config.ts ├── exports ├── canvas-shaders.ts ├── canvas.ts ├── index.ts ├── inspector.ts ├── utils.ts ├── webgl-shaders.ts └── webgl.ts ├── package.json ├── performance ├── .gitignore ├── bun.lockb ├── index.ts ├── package.json ├── readme.md ├── src │ ├── CoreNode.ts │ ├── ImageTexture.ts │ ├── Tree.ts │ ├── WebGlContextWrapper.ts │ └── utils │ │ └── types.ts └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── src ├── common │ ├── CommonTypes.ts │ ├── EventEmitter.ts │ ├── IAnimationController.ts │ └── IEventEmitter.ts ├── core │ ├── CoreNode.test.ts │ ├── CoreNode.ts │ ├── CoreShaderManager.ts │ ├── CoreTextNode.ts │ ├── CoreTextureManager.ts │ ├── Stage.ts │ ├── TextureMemoryManager.ts │ ├── animations │ │ ├── AnimationManager.ts │ │ ├── CoreAnimation.ts │ │ └── CoreAnimationController.ts │ ├── lib │ │ ├── ContextSpy.ts │ │ ├── ImageWorker.ts │ │ ├── Matrix3d.ts │ │ ├── RenderCoords.ts │ │ ├── WebGlContextWrapper.ts │ │ ├── textureCompression.ts │ │ ├── textureSvg.ts │ │ ├── utils.ts │ │ └── validateImageBitmap.ts │ ├── platforms │ │ ├── Platform.ts │ │ └── web │ │ │ └── WebPlatform.ts │ ├── renderers │ │ ├── CoreContextTexture.ts │ │ ├── CoreRenderOp.ts │ │ ├── CoreRenderer.ts │ │ ├── CoreShaderNode.ts │ │ ├── CoreShaderProgram.ts │ │ ├── canvas │ │ │ ├── CanvasRenderer.ts │ │ │ ├── CanvasShaderNode.ts │ │ │ ├── CanvasTexture.ts │ │ │ └── internal │ │ │ │ ├── C2DShaderUtils.ts │ │ │ │ └── ColorUtils.ts │ │ └── webgl │ │ │ ├── WebGlCtxRenderTexture.ts │ │ │ ├── WebGlCtxSubTexture.ts │ │ │ ├── WebGlCtxTexture.ts │ │ │ ├── WebGlRenderOp.ts │ │ │ ├── WebGlRenderer.ts │ │ │ ├── WebGlShaderNode.ts │ │ │ ├── WebGlShaderProgram.ts │ │ │ └── internal │ │ │ ├── BufferCollection.ts │ │ │ ├── RendererUtils.ts │ │ │ ├── ShaderUtils.ts │ │ │ └── WebGlUtils.ts │ ├── shaders │ │ ├── canvas │ │ │ ├── Border.ts │ │ │ ├── HolePunch.ts │ │ │ ├── LinearGradient.ts │ │ │ ├── RadialGradient.ts │ │ │ ├── Rounded.ts │ │ │ ├── RoundedWithBorder.ts │ │ │ ├── RoundedWithBorderAndShadow.ts │ │ │ ├── RoundedWithShadow.ts │ │ │ ├── Shadow.ts │ │ │ └── utils │ │ │ │ └── render.ts │ │ ├── templates │ │ │ ├── BorderTemplate.ts │ │ │ ├── HolePunchTemplate.ts │ │ │ ├── LinearGradientTemplate.ts │ │ │ ├── RadialGradientTemplate.ts │ │ │ ├── RoundedTemplate.ts │ │ │ ├── RoundedWithBorderAndShadowTemplate.ts │ │ │ ├── RoundedWithBorderTemplate.ts │ │ │ ├── RoundedWithShadowTemplate.ts │ │ │ └── ShadowTemplate.ts │ │ ├── utils.ts │ │ └── webgl │ │ │ ├── Border.ts │ │ │ ├── Default.ts │ │ │ ├── DefaultBatched.ts │ │ │ ├── HolePunch.ts │ │ │ ├── LinearGradient.ts │ │ │ ├── RadialGradient.ts │ │ │ ├── Rounded.ts │ │ │ ├── RoundedWithBorder.ts │ │ │ ├── RoundedWithBorderAndShadow.ts │ │ │ ├── RoundedWithShadow.ts │ │ │ ├── SdfShader.ts │ │ │ └── Shadow.ts │ ├── text-rendering │ │ ├── TextRenderingUtils.ts │ │ ├── TextTextureRendererUtils.ts │ │ ├── TrFontManager.ts │ │ ├── font-face-types │ │ │ ├── SdfTrFontFace │ │ │ │ ├── SdfTrFontFace.ts │ │ │ │ └── internal │ │ │ │ │ ├── FontShaper.ts │ │ │ │ │ ├── SdfFontShaper.test.ts │ │ │ │ │ └── SdfFontShaper.ts │ │ │ ├── TrFontFace.ts │ │ │ ├── WebTrFontFace.ts │ │ │ └── utils.ts │ │ └── renderers │ │ │ ├── CanvasTextRenderer.ts │ │ │ ├── LightningTextTextureRenderer.ts │ │ │ ├── SdfTextRenderer │ │ │ ├── SdfTextRenderer.ts │ │ │ └── internal │ │ │ │ ├── PeekableGenerator.test.ts │ │ │ │ ├── PeekableGenerator.ts │ │ │ │ ├── SpecialCodepoints.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── getStartConditions.ts │ │ │ │ ├── getUnicodeCodepoints.test.ts │ │ │ │ ├── getUnicodeCodepoints.ts │ │ │ │ ├── layoutText.ts │ │ │ │ ├── measureText.test.ts │ │ │ │ ├── measureText.ts │ │ │ │ ├── setRenderWindow.test.ts │ │ │ │ ├── setRenderWindow.ts │ │ │ │ └── util.ts │ │ │ └── TextRenderer.ts │ ├── textures │ │ ├── ColorTexture.ts │ │ ├── ImageTexture.ts │ │ ├── NoiseTexture.ts │ │ ├── RenderTexture.ts │ │ ├── SubTexture.ts │ │ └── Texture.ts │ └── utils.ts ├── env.d.ts ├── main-api │ ├── INode.ts │ ├── Inspector.ts │ ├── Renderer.ts │ └── utils.ts └── utils.ts ├── test └── mockdata │ └── Ubuntu-Bold.msdf.json ├── tsconfig.cfg.json ├── tsconfig.dist.json ├── tsconfig.json ├── tsconfig.vitest.json ├── typedoc.config.cjs ├── visual-regression ├── .npmrc ├── DOCKER.md ├── README.md ├── certified-snapshots │ └── chromium-ci │ │ ├── alignment-1.png │ │ ├── alpha-1.png │ │ ├── alpha-blending-1.png │ │ ├── alpha-blending-2.png │ │ ├── animation-events_a1-1.png │ │ ├── animation-events_a1-2.png │ │ ├── animation-events_a1-3.png │ │ ├── animation-events_a2-1.png │ │ ├── animation-events_a2-2.png │ │ ├── animation-events_a2-3.png │ │ ├── animation-events_a3-1.png │ │ ├── animation-events_a3-2.png │ │ ├── clear-color-setting-1.png │ │ ├── clear-color-setting-2.png │ │ ├── clear-color-setting-3.png │ │ ├── clipping-1.png │ │ ├── clipping-2.png │ │ ├── clipping-3.png │ │ ├── clipping-mutations-1.png │ │ ├── clipping-mutations-2.png │ │ ├── clipping-mutations-3.png │ │ ├── destroy-1.png │ │ ├── destroy-2.png │ │ ├── ds-effect-radial-progress-1.png │ │ ├── dynamic-shader-1.png │ │ ├── dynamic-shader-circle-border-radius-1.png │ │ ├── hole-punch-effect-1.png │ │ ├── quads-rendered-1.png │ │ ├── quads-rendered-2.png │ │ ├── render-settings-1.png │ │ ├── render-settings-2.png │ │ ├── render-settings-3.png │ │ ├── render-settings-4.png │ │ ├── render-settings-5.png │ │ ├── render-settings-6.png │ │ ├── resize-mode-1.png │ │ ├── resize-mode-2.png │ │ ├── resize-mode-3.png │ │ ├── resize-mode-4.png │ │ ├── rtt-dimension-1.png │ │ ├── rtt-dimension-2.png │ │ ├── rtt-dimension-3.png │ │ ├── rtt-dimension-4.png │ │ ├── rtt-dimension-5.png │ │ ├── rtt-dimension-6.png │ │ ├── rtt-spritemap-1.png │ │ ├── scaling-1.png │ │ ├── scaling-2.png │ │ ├── scaling-3.png │ │ ├── shader-animation_animation1-1.png │ │ ├── shader-animation_animation2-1.png │ │ ├── shader-animation_startup-1.png │ │ ├── shader-border-1.png │ │ ├── shader-hole-punch-1.png │ │ ├── shader-linear-gradient-1.png │ │ ├── shader-radial-gradient-1.png │ │ ├── shader-rounded-1.png │ │ ├── shader-shadow-1.png │ │ ├── text-align-1.png │ │ ├── text-align-2.png │ │ ├── text-align-3.png │ │ ├── text-align-4.png │ │ ├── text-align-5.png │ │ ├── text-align-6.png │ │ ├── text-alpha-1.png │ │ ├── text-alpha-2.png │ │ ├── text-baseline-1.png │ │ ├── text-canvas-font-no-metrics-1.png │ │ ├── text-canvas-font-no-metrics-2.png │ │ ├── text-contain-1.png │ │ ├── text-contain-10.png │ │ ├── text-contain-2.png │ │ ├── text-contain-3.png │ │ ├── text-contain-4.png │ │ ├── text-contain-5.png │ │ ├── text-contain-6.png │ │ ├── text-contain-7.png │ │ ├── text-contain-8.png │ │ ├── text-contain-9.png │ │ ├── text-dimensions-1.png │ │ ├── text-dimensions-2.png │ │ ├── text-dimensions-3.png │ │ ├── text-dimensions-4.png │ │ ├── text-dimensions-5.png │ │ ├── text-dimensions-6.png │ │ ├── text-dimensions-7.png │ │ ├── text-layout-consistency-1.png │ │ ├── text-layout-consistency-2.png │ │ ├── text-layout-consistency-3.png │ │ ├── text-layout-consistency-modified-metrics-1.png │ │ ├── text-layout-consistency-modified-metrics-2.png │ │ ├── text-layout-consistency-modified-metrics-3.png │ │ ├── text-line-height-1.png │ │ ├── text-max-lines-1.png │ │ ├── text-max-lines-2.png │ │ ├── text-mixed-1.png │ │ ├── text-offscreen-move-1.png │ │ ├── text-offscreen-move-2.png │ │ ├── text-offscreen-move-3.png │ │ ├── text-offscreen-move-4.png │ │ ├── text-offscreen-move-5.png │ │ ├── text-offscreen-move-6.png │ │ ├── text-overflow-suffix-1.png │ │ ├── text-rotation-1.png │ │ ├── text-rotation-2.png │ │ ├── text-scaling-1.png │ │ ├── text-scaling-2.png │ │ ├── text-scaling-3.png │ │ ├── text-scaling-4.png │ │ ├── text-scaling-5.png │ │ ├── text-scaling-6.png │ │ ├── text-ssdf-1.png │ │ ├── text-vertical-align-1.png │ │ ├── text-vertical-align-2.png │ │ ├── text-wordbreak-1.png │ │ ├── text-wordbreak-2.png │ │ ├── text-wordbreak-3.png │ │ ├── text-wordbreak-4.png │ │ ├── text-zwsp-1.png │ │ ├── text-zwsp-2.png │ │ ├── text-zwsp-3.png │ │ ├── texture-autosize-1.png │ │ ├── texture-base64-1.png │ │ ├── texture-factory-1.png │ │ ├── texture-source-1.png │ │ ├── texture-spritemap-1.png │ │ ├── texture-svg-1.png │ │ ├── textures-1.png │ │ ├── viewport-boundsmargin-1.png │ │ ├── viewport-boundsmargin-10.png │ │ ├── viewport-boundsmargin-11.png │ │ ├── viewport-boundsmargin-12.png │ │ ├── viewport-boundsmargin-2.png │ │ ├── viewport-boundsmargin-3.png │ │ ├── viewport-boundsmargin-4.png │ │ ├── viewport-boundsmargin-5.png │ │ ├── viewport-boundsmargin-6.png │ │ ├── viewport-boundsmargin-7.png │ │ ├── viewport-boundsmargin-8.png │ │ ├── viewport-boundsmargin-9.png │ │ ├── viewport-events-1.png │ │ ├── viewport-events-10.png │ │ ├── viewport-events-11.png │ │ ├── viewport-events-12.png │ │ ├── viewport-events-13.png │ │ ├── viewport-events-14.png │ │ ├── viewport-events-15.png │ │ ├── viewport-events-16.png │ │ ├── viewport-events-17.png │ │ ├── viewport-events-18.png │ │ ├── viewport-events-2.png │ │ ├── viewport-events-3.png │ │ ├── viewport-events-4.png │ │ ├── viewport-events-5.png │ │ ├── viewport-events-6.png │ │ ├── viewport-events-7.png │ │ ├── viewport-events-8.png │ │ ├── viewport-events-9.png │ │ ├── viewport-largebound-1.png │ │ ├── viewport-largebound-2.png │ │ ├── viewport-largebound-3.png │ │ ├── viewport-strictbounds-1.png │ │ ├── viewport-strictbounds-2.png │ │ ├── viewport-strictbounds-3.png │ │ └── zIndex-1.png ├── package.json ├── src │ ├── build-docker.ts │ ├── detectDockerRuntime.ts │ ├── index.ts │ └── snapshot.ts └── tsconfig.json └── vitest.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | insert_final_newline = true 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | max_line_length = 80 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml: -------------------------------------------------------------------------------- 1 | name: "💡 Feature Request" 2 | description: Create a new ticket for a new feature request 3 | title: "💡 [REQUEST] - " 4 | labels: [ 5 | "question" 6 | ] 7 | body: 8 | - type: textarea 9 | id: implementation_pr 10 | attributes: 11 | label: "Implementation PR" 12 | description: Pull request used 13 | placeholder: "#Pull Request ID" 14 | validations: 15 | required: false 16 | - type: textarea 17 | id: reference_issues 18 | attributes: 19 | label: "Reference Issues" 20 | description: Common issues 21 | placeholder: "#Issues IDs" 22 | validations: 23 | required: false 24 | - type: textarea 25 | id: summary 26 | attributes: 27 | label: "Summary" 28 | description: Provide a brief explanation of the feature 29 | placeholder: Describe in a few lines your feature request 30 | validations: 31 | required: true 32 | - type: textarea 33 | id: basic_example 34 | attributes: 35 | label: "Basic Example" 36 | description: Indicate here some basic examples of your feature. 37 | placeholder: A few specific words about your feature request. 38 | validations: 39 | required: true 40 | - type: textarea 41 | id: drawbacks 42 | attributes: 43 | label: "Drawbacks" 44 | description: What are the drawbacks/impacts of your feature request ? 45 | placeholder: Identify the drawbacks and impacts while being neutral on your feature request 46 | validations: 47 | required: true 48 | - type: textarea 49 | id: unresolved_question 50 | attributes: 51 | label: "Unresolved questions" 52 | description: What questions still remain unresolved ? 53 | placeholder: Identify any unresolved issues. 54 | validations: 55 | required: false 56 | -------------------------------------------------------------------------------- /.github/workflows/examples.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Examples 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | concurrency: 15 | group: "pages" 16 | cancel-in-progress: false 17 | 18 | jobs: 19 | deploy: 20 | environment: 21 | name: github-pages 22 | url: ${{ steps.deployment.outputs.page_url }} 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Install Node.js 29 | uses: actions/setup-node@v3 30 | with: 31 | node-version: 20 32 | 33 | - uses: pnpm/action-setup@v4 34 | name: Install pnpm 35 | with: 36 | run_install: false 37 | 38 | - name: Get pnpm store directory 39 | shell: bash 40 | run: | 41 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 42 | 43 | - uses: actions/cache@v3 44 | name: Setup pnpm cache 45 | with: 46 | path: ${{ env.STORE_PATH }} 47 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 48 | restore-keys: | 49 | ${{ runner.os }}-pnpm-store- 50 | 51 | - name: Install dependencies 52 | run: pnpm install 53 | 54 | - name: Build renderer 55 | run: pnpm build 56 | 57 | - name: Build examples 58 | run: cd examples && pnpm build 59 | 60 | - name: Setup Pages 61 | uses: actions/configure-pages@v5 62 | 63 | - name: Upload artifact 64 | uses: actions/upload-pages-artifact@v3 65 | with: 66 | path: './examples/dist' 67 | 68 | - name: Deploy to GitHub Pages 69 | id: deployment 70 | uses: actions/deploy-pages@v4 71 | -------------------------------------------------------------------------------- /.github/workflows/inactive.yaml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v9 14 | with: 15 | days-before-issue-stale: 180 16 | days-before-issue-close: 7 17 | stale-issue-label: "stale" 18 | stale-issue-message: "This issue is stale because it has been open for 180 days with no activity. It will be closed in 7 days if no further activity occurs." 19 | close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale." 20 | days-before-pr-stale: 180 21 | days-before-pr-close: 7 22 | stale-pr-message: "This pull request is stale because it has been open for 180 days with no activity. It will be closed in 7 days if no further activity occurs." 23 | close-pr-message: "This pull request was closed because it has been inactive for 7 days since being marked as stale." 24 | repo-token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | merge_group: 4 | types: [checks_requested] 5 | jobs: 6 | run-all-tests: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v3 12 | 13 | - name: Install Node.js 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version: 20 17 | 18 | - uses: pnpm/action-setup@v4 19 | name: Install pnpm 20 | with: 21 | run_install: false 22 | 23 | - name: Get pnpm store directory 24 | shell: bash 25 | run: | 26 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 27 | 28 | - uses: actions/cache@v3 29 | name: Setup pnpm cache 30 | with: 31 | path: ${{ env.STORE_PATH }} 32 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 33 | restore-keys: | 34 | ${{ runner.os }}-pnpm-store- 35 | 36 | - name: Install dependencies 37 | run: pnpm install 38 | 39 | - name: Run Unit Tests 40 | run: pnpm test 41 | 42 | - name: Install Playwright Browser 43 | run: cd visual-regression && pnpm exec playwright install chromium 44 | 45 | - name: Run Visual Regression Tests 46 | run: pnpm run test:visual --color 47 | env: 48 | RUNTIME_ENV: ci 49 | 50 | - name: Upload failed-results as artifact 51 | if: ${{ failure() }} 52 | uses: actions/upload-artifact@v4 53 | with: 54 | name: failed-results 55 | path: visual-regression/failed-results/ 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_store 3 | .idea 4 | typedocs 5 | dist 6 | dist-* 7 | examples/dist-tsc 8 | visual-regression/failed-results 9 | visual-regression/certified-snapshots/*-local 10 | build 11 | releases 12 | .tmp 13 | .env 14 | *.tgz 15 | .pnpm-store 16 | # This project uses `pnpm` for package management 17 | package-lock.json 18 | .vscode/launch.json 19 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | # If files exist in the `visual-regression/failed-results` directory, fail the commit 5 | if [ -n "$(ls -A visual-regression/failed-results)" ]; then 6 | echo "Failed Visual Regression Test results found in \`visual-regression/failed-results\`. Please fix them before committing." 7 | exit 1 8 | fi 9 | 10 | pnpm exec lint-staged 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict = true 2 | use-node-version = 20.9.0 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_store 3 | .idea 4 | dist 5 | build 6 | releases 7 | .tmp 8 | .env 9 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true 4 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "editorconfig.editorconfig", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": false, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.codeActionsOnSave": [ 5 | "source.formatDocument", 6 | "source.fixAll.eslint" 7 | ], 8 | "[typescript]": { 9 | "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you would like to contribute code to this project you can do so through GitHub by forking the repository 4 | and sending a pull request. 5 | Before RDK accepts your code into the project you must sign the RDK Contributor License Agreement (CLA). 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | LICENSE -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Playwright's base image 2 | FROM mcr.microsoft.com/playwright:v1.49.0-jammy 3 | 4 | # Set the working directory 5 | WORKDIR /work 6 | 7 | # Copy the necessary files to the container 8 | COPY .npmrc .npmrc 9 | COPY package.json package.json 10 | 11 | # Install PNPM 12 | RUN corepack enable && corepack prepare pnpm@8.15.5 --activate 13 | 14 | # Get pnpm to install the version of Node declared in .npmrc 15 | RUN pnpm exec ls 16 | 17 | # Set the entry point command 18 | CMD ["/bin/bash", "-c", "echo 'Must run with Visual Regression Test Runner: `pnpm run test:visual --ci`'"] 19 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This component contains software that is Copyright 2023 Comcast Cable Communications Management, LLC. 2 | The component is licensed to you under the Apache License, Version 2.0 (the "License"). 3 | You may not use the component except in compliance with the License. 4 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Procedure 2 | 3 | Publish a new release with the below instructions, you must first be a contributor 4 | who is authorized to both push directly to this repo and publish packages to the 5 | lightningjs NPM scope. 6 | 7 | ## Mark, push and publish the release 8 | 9 | ``` 10 | # Make sure you're on the main branch 11 | git checkout main 12 | 13 | # Stash any untracked + uncomitted changes 14 | git stash -u 15 | 16 | # Pull any new commits from GitHub 17 | git pull 18 | 19 | # Run the unit tests 20 | pnpm test 21 | 22 | # Run the Visual Regression Tests in CI mode 23 | pnpm test:visual --ci 24 | 25 | # Review changes in order to decide which release-increment to use 26 | git log --first-parent main...v<last-version-number> 27 | 28 | # Mark the version update 29 | # This creates a new tagged commit for the version 30 | pnpm version <release-increment> # patch/minor/major 31 | 32 | # Publish the package to NPM 33 | pnpm publish --access public 34 | 35 | # Push version commit to github 36 | git push 37 | 38 | # Push version tag to github 39 | git push origin vX.X.X 40 | 41 | # Pop the stash (if one was created) 42 | git stash pop 43 | ``` 44 | 45 | ## Generate a release on GitHub 46 | 47 | 1. Go to https://github.com/lightning-js/renderer/releases/new 48 | 2. Choose a Tag: _Choose the newly pushed tag_ 49 | 3. Target: _main_ 50 | 4. Name the release with the same name as the tag: vX.X.X 51 | 5. Click "Generate release notes" 52 | 6. Edit the release notes as appropriate: 53 | - User facing changes should go under the main "What's Changed" heading 54 | - Mark all breaking changes with: :warning: **Breaking Change:** (Description) 55 | - Move any changes specific to performance to a new level 3 heading called: **Performance** 56 | - If there are other non-user facing changes move them to a new level 3 heading called: **Non-User Facing**. 57 | 7. Set as the latest release: _Check_ 58 | 8. Click "Publish release" 59 | -------------------------------------------------------------------------------- /docs/CustomShaderEffectTexture.md: -------------------------------------------------------------------------------- 1 | # Custom Shaders / Effects / Textures 2 | 3 | For some examples on how to create custom shaders, effects and textures, see 4 | the (custom-shader-effect-texture)[./example-projects/custom-shader-effect-texture] 5 | example project. 6 | -------------------------------------------------------------------------------- /docs/ManualRegressionTests.md: -------------------------------------------------------------------------------- 1 | # Manual Regression Tests 2 | 3 | In addition to the automated [Visual Regression Tests](../visual-regression/README.md), 4 | there are some tests that should be run manually on embedded devices to ensure 5 | the Renderer is working properly. 6 | 7 | ## Critical Texture Memory Cleanup Test 8 | 9 | `?test=texture-cleanup-critical&monitor=true` 10 | 11 | This test confirms the Renderer's ability to clean up textures when it never 12 | has a chance to perform Idle Texture Cleanups. 13 | 14 | Within an infinite loop, the test updates the texture of a single full screen 15 | background node to a new random NoiseTexture in rapid succession. 16 | 17 | **Expected Results**: The tests runs for at least 30 mins minutes without 18 | crashing or the visible Nodes becoming black. The Memory Monitor shows loaded 19 | textures reaching the Critical Threshold and then falling back to the target. 20 | 21 | To further confirm that the textures are being properly disposed of, you can use 22 | the Chrome Task Manager to monitor the GPU's memory usage: 23 | 24 | 1. Click Window > Task Manager 25 | 2. Locate the "GPU Process" 26 | 3. Observe the "Memory Footprint" column 27 | 4. Like the Memory Monitor, the value should increase, and fall significantly 28 | repeatedly. 29 | 30 | ## Idle Texture Memory Cleanup Test 31 | 32 | `?test=texture-cleanup-idle&monitor=true` 33 | 34 | This test confirms the Renderer's ability to clean up textures that are no longer 35 | renderable (not in the configured `boundsMargin`) from GPU VRAM when the Renderer 36 | becomes idle. 37 | 38 | Within an infinite loop, this test generates a grid of Nodes with random NoiseTextures 39 | assigned first completely visible on screen (for at least a frame) and then moves 40 | them outside of the configured `boundsMargin` before repeating the loop. 41 | 42 | **Expected Results**: The tests runs for at least 30 mins minutes without 43 | crashing or the visible Nodes becoming black. The Memory Monitor shows loaded 44 | textures falling to the Target Threshold roughly every 5 seconds. 45 | 46 | To further test that the textures are being properly disposed of, you can use the Chrome Task Manager to monitor the GPU's memory usage: 47 | 48 | 1. Click Window > Task Manager 49 | 2. Locate the "GPU Process" 50 | 3. Observe the "Memory Footprint" column 51 | 4. Like the Memory Monitor, the value should increase, and fall significantly 52 | repeatedly. 53 | -------------------------------------------------------------------------------- /docs/NodeDependencyGraph.md: -------------------------------------------------------------------------------- 1 | # Node Depenedency Graph 2 | 3 | The diagram below describes the reactive flow of inputs into cached calculated data elements that are updated during each `update()` of a Core Node. 4 | 5 | ![Dependency graph describing by way of a water fall the input and output relationship of calculated (and cached) data elements of a node](./images/dependency-graph.png) 6 | -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/index.html: -------------------------------------------------------------------------------- 1 | <html> 2 | <head> 3 | <title>Renderer Browser Test 4 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "renderer-custom-shader", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "vite --open --host", 9 | "build": "tsc && vite build", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@lightningjs/renderer": "link:../../.." 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20.12.12", 20 | "typescript": "^5.4.5", 21 | "vite": "^5.2.11" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/pnpm-workspace.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/docs/example-projects/custom-shader-effect-texture/pnpm-workspace.yaml -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/src/assets/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/docs/example-projects/custom-shader-effect-texture/src/assets/robot.png -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/src/index.ts: -------------------------------------------------------------------------------- 1 | import { RendererMain } from '@lightningjs/renderer'; 2 | import { 3 | SdfTextRenderer, 4 | WebGlCoreRenderer, 5 | } from '@lightningjs/renderer/webgl'; 6 | import { CanvasTextRenderer } from '@lightningjs/renderer/canvas'; 7 | import { Inspector } from '@lightningjs/renderer/inspector'; 8 | import { MyCustomShader } from './MyCustomShader.js'; 9 | import { MyCustomTexture } from './MyCustomTexture.js'; 10 | import robotImg from './assets/robot.png'; 11 | 12 | (async () => { 13 | const renderer = new RendererMain( 14 | { 15 | appWidth: 1920, 16 | appHeight: 1080, 17 | boundsMargin: [100, 100, 100, 100], 18 | clearColor: 0x000000ff, 19 | fpsUpdateInterval: 1000, 20 | enableContextSpy: false, 21 | inspector: Inspector, 22 | renderEngine: WebGlCoreRenderer, 23 | fontEngines: [SdfTextRenderer, CanvasTextRenderer], 24 | }, 25 | 'app', 26 | ); 27 | 28 | renderer.stage.shManager.registerShaderType('MyCustomShader', MyCustomShader); 29 | renderer.stage.txManager.registerTextureType( 30 | 'MyCustomTexture', 31 | MyCustomTexture, 32 | ); 33 | 34 | const distortedBot = renderer.createNode({ 35 | width: 300, 36 | height: 300, 37 | src: robotImg, 38 | parent: renderer.root, 39 | shader: renderer.createShader('MyCustomShader', { 40 | normalized: true, 41 | topLeft: { x: 0.5, y: 0 }, 42 | topRight: { x: 0.500001, y: 0 }, 43 | bottomRight: { x: 1, y: 1 }, 44 | bottomLeft: { x: 0, y: 1 }, 45 | }), 46 | }); 47 | 48 | const pacman = renderer.createNode({ 49 | x: 600, 50 | width: 300, 51 | height: 300, 52 | texture: renderer.createTexture('MyCustomTexture', { 53 | percent: 5, 54 | width: 300, 55 | height: 300, 56 | }), 57 | parent: renderer.root, 58 | }); 59 | })().catch(console.error); 60 | -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /// 21 | // This enables Vite's import.meta augmentations and possibly other things? 22 | -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/tsconfig.cfg.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist-cfg", 4 | "types": ["@types/node"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleResolution": "node", 8 | "composite": true, 9 | "resolveJsonModule": true, 10 | "allowJs": true, 11 | "esModuleInterop": true, 12 | }, 13 | "files": [ 14 | "./vite.config.ts", 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /docs/example-projects/custom-shader-effect-texture/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "types": [], 5 | "lib": ["ES2022", "DOM"], 6 | "outDir": "dist-tsc", 7 | "target": "ES2022", 8 | "module": "Node16", 9 | "moduleResolution": "Node16", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "experimentalDecorators": true, 13 | 14 | // Type Checking / Syntax Rules 15 | "strict": true, 16 | "noUncheckedIndexedAccess": true, 17 | "noImplicitOverride": true, 18 | "allowSyntheticDefaultImports": true, 19 | "resolveJsonModule": true, 20 | "verbatimModuleSyntax": true, 21 | "composite": true, 22 | }, 23 | "include": [ 24 | "./src/**/*.ts" 25 | ], 26 | "exclude": ["node_modules", "./**/*.test.ts"], 27 | "references": [ 28 | { 29 | "path": "./tsconfig.cfg.json" 30 | } 31 | ], 32 | } 33 | 34 | -------------------------------------------------------------------------------- /docs/images/dependency-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/docs/images/dependency-graph.png -------------------------------------------------------------------------------- /docs/images/dependency-graph.txt: -------------------------------------------------------------------------------- 1 | Source: 2 | https://lucid.app/lucidchart/f5c48c94-6096-44c5-bca2-97fe2b581095/edit?viewport_loc=-1167%2C-285%2C4800%2C2244%2Cm8WTkWxK2plY&invitationId=inv_44218a81-5bb9-4436-a5e6-5697c146e164 3 | https://lucid.app/publicSegments/view/a6dc7e53-0327-46c7-b351-895dc8034af2/image.png 4 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import eslintPluginTs from '@typescript-eslint/eslint-plugin'; 2 | import tsParser from '@typescript-eslint/parser'; 3 | 4 | export default [ 5 | { 6 | files: ['**/*.ts'], 7 | languageOptions: { 8 | parser: tsParser, 9 | parserOptions: { 10 | ecmaVersion: 2022, 11 | sourceType: 'module', 12 | project: [ 13 | './tsconfig.json', 14 | './tsconfig.vitest.json', 15 | './tsconfig.cfg.json', 16 | './examples/tsconfig.json', 17 | './visual-regression/tsconfig.json', 18 | './performance/tsconfig.json', 19 | ], 20 | }, 21 | }, 22 | plugins: { 23 | '@typescript-eslint': eslintPluginTs, 24 | }, 25 | rules: { 26 | ...eslintPluginTs.configs.recommended.rules, 27 | '@typescript-eslint/no-unsafe-argument': 'warn', 28 | '@typescript-eslint/no-unsafe-assignment': 'warn', 29 | '@typescript-eslint/no-unsafe-return': 'warn', 30 | '@typescript-eslint/no-unsafe-call': 'warn', 31 | '@typescript-eslint/no-non-null-assertion': 'warn', 32 | '@typescript-eslint/no-unsafe-member-access': 'warn', 33 | '@typescript-eslint/ban-ts-comment': 'warn', 34 | '@typescript-eslint/no-explicit-any': 'warn', 35 | '@typescript-eslint/no-unused-vars': 'warn', 36 | '@typescript-eslint/no-empty-object-type': 'warn', 37 | '@typescript-eslint/no-unused-expressions': 'warn', 38 | }, 39 | }, 40 | { 41 | ignores: [ 42 | '**/dist/**', 43 | 'node_modules', 44 | '**config**.ts', 45 | '**/docs/**', 46 | 'dist-vitest', 47 | 'dist-cfg', 48 | ], 49 | }, 50 | ]; 51 | -------------------------------------------------------------------------------- /examples/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict = true 2 | -------------------------------------------------------------------------------- /examples/assets/elevator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/elevator.png -------------------------------------------------------------------------------- /examples/assets/green-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/green-100.png -------------------------------------------------------------------------------- /examples/assets/green-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/green-25.png -------------------------------------------------------------------------------- /examples/assets/green-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/green-50.png -------------------------------------------------------------------------------- /examples/assets/green-50.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/green-50.psd -------------------------------------------------------------------------------- /examples/assets/lightning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/lightning.png -------------------------------------------------------------------------------- /examples/assets/red-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/red-100.png -------------------------------------------------------------------------------- /examples/assets/red-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/red-25.png -------------------------------------------------------------------------------- /examples/assets/red-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/red-50.png -------------------------------------------------------------------------------- /examples/assets/robot/elevator-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/elevator-background.png -------------------------------------------------------------------------------- /examples/assets/robot/elevator-door-bottom-top-floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/elevator-door-bottom-top-floor.png -------------------------------------------------------------------------------- /examples/assets/robot/elevator-door-left-ground-floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/elevator-door-left-ground-floor.png -------------------------------------------------------------------------------- /examples/assets/robot/elevator-door-right-ground-floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/elevator-door-right-ground-floor.png -------------------------------------------------------------------------------- /examples/assets/robot/elevator-door-shadow-ground-floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/elevator-door-shadow-ground-floor.png -------------------------------------------------------------------------------- /examples/assets/robot/elevator-door-top-top-floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/elevator-door-top-top-floor.png -------------------------------------------------------------------------------- /examples/assets/robot/environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/environment.png -------------------------------------------------------------------------------- /examples/assets/robot/robot-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/robot-shadow.png -------------------------------------------------------------------------------- /examples/assets/robot/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/robot/robot.png -------------------------------------------------------------------------------- /examples/assets/rocko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/rocko.png -------------------------------------------------------------------------------- /examples/assets/spritemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/spritemap.png -------------------------------------------------------------------------------- /examples/assets/test-etc1.pvr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/test-etc1.pvr -------------------------------------------------------------------------------- /examples/assets/test-s3tc.ktx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/test-s3tc.ktx -------------------------------------------------------------------------------- /examples/assets/testscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/testscreen.png -------------------------------------------------------------------------------- /examples/assets/testscreen_rotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/assets/testscreen_rotated.png -------------------------------------------------------------------------------- /examples/common/Component.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { INode, INodeProps, RendererMain } from '@lightningjs/renderer'; 21 | 22 | export class Component { 23 | readonly node: INode; 24 | 25 | constructor(readonly renderer: RendererMain, nodeProps: Partial) { 26 | this.node = renderer.createNode({ 27 | ...nodeProps, 28 | }); 29 | } 30 | 31 | get x() { 32 | return this.node.x; 33 | } 34 | 35 | set x(x: number) { 36 | this.node.x = x; 37 | } 38 | 39 | get y() { 40 | return this.node.y; 41 | } 42 | 43 | set y(y: number) { 44 | this.node.y = y; 45 | } 46 | 47 | get width() { 48 | return this.node.width; 49 | } 50 | 51 | set width(width: number) { 52 | this.node.width = width; 53 | } 54 | 55 | get height() { 56 | return this.node.height; 57 | } 58 | 59 | set height(height: number) { 60 | this.node.height = height; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /examples/common/LocalStorage.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | // Retreive state from local storage (if localStorage is available) 21 | // and set the state of the app accordingly. 22 | export function loadStorage(testName: string): Partial | null { 23 | if (typeof window.localStorage === 'undefined') { 24 | return null; 25 | } 26 | try { 27 | const serializedState = localStorage.getItem(`${testName}-state`); 28 | if (serializedState === null) { 29 | return null; 30 | } 31 | return JSON.parse(serializedState); 32 | } catch (err) { 33 | return null; 34 | } 35 | } 36 | 37 | // Save the state of the app to local storage (if localStorage is available). 38 | export function saveStorage(testName: string, state: Partial): void { 39 | if (typeof window.localStorage === 'undefined') { 40 | return; 41 | } 42 | try { 43 | const serializedState = JSON.stringify(state); 44 | localStorage.setItem(`${testName}-state`, serializedState); 45 | } catch (err) { 46 | // Ignore write errors. 47 | } 48 | } 49 | 50 | // Clear the state of the app from local storage (if localStorage is available). 51 | export function clearStorage(testName: string): void { 52 | if (typeof window.localStorage === 'undefined') { 53 | return; 54 | } 55 | try { 56 | localStorage.removeItem(`${testName}-state`); 57 | } catch (err) { 58 | // Ignore write errors. 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/common/installShaders.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import { type Stage } from '@lightningjs/renderer'; 19 | 20 | export async function installShaders(stage: Stage, renderMode: string) { 21 | let shaders; 22 | if (renderMode === 'webgl') { 23 | shaders = await import('@lightningjs/renderer/webgl/shaders'); 24 | } else if (renderMode === 'canvas') { 25 | shaders = await import('@lightningjs/renderer/canvas/shaders'); 26 | } 27 | stage.shManager.registerShaderType('Rounded', shaders.Rounded); 28 | stage.shManager.registerShaderType( 29 | 'RoundedWithBorder', 30 | shaders.RoundedWithBorder, 31 | ); 32 | stage.shManager.registerShaderType( 33 | 'RoundedWithShadow', 34 | shaders.RoundedWithShadow, 35 | ); 36 | stage.shManager.registerShaderType( 37 | 'RoundedWithBorderAndShadow', 38 | shaders.RoundedWithBorderAndShadow, 39 | ); 40 | stage.shManager.registerShaderType('Border', shaders.Border); 41 | stage.shManager.registerShaderType('Shadow', shaders.Shadow); 42 | stage.shManager.registerShaderType('HolePunch', shaders.HolePunch); 43 | stage.shManager.registerShaderType('RadialGradient', shaders.RadialGradient); 44 | stage.shManager.registerShaderType('LinearGradient', shaders.LinearGradient); 45 | } 46 | -------------------------------------------------------------------------------- /examples/common/setupMathRandom.ts: -------------------------------------------------------------------------------- 1 | export async function setupMathRandom() { 2 | const mt19937 = await import('@stdlib/random-base-mt19937'); 3 | 4 | const factory = mt19937.factory || mt19937.default.factory; 5 | const rand = factory({ seed: 1234 }); 6 | Math.random = function () { 7 | return rand() / rand.MAX; 8 | }; 9 | console.log('Math.random overridden with mt19937'); 10 | } 11 | -------------------------------------------------------------------------------- /examples/common/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { 21 | Dimensions, 22 | NodeTextLoadedPayload, 23 | INode, 24 | ITextNode, 25 | } from '@lightningjs/renderer'; 26 | 27 | export async function waitForLoadedDimensions( 28 | node: INode | ITextNode, 29 | ): Promise { 30 | return new Promise((resolve) => { 31 | node.once('loaded', (_node: INode, payload: NodeTextLoadedPayload) => { 32 | const { width, height } = payload.dimensions; 33 | resolve({ 34 | width, 35 | height, 36 | }); 37 | }); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Renderer Browser Test 4 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type": "module", 6 | "main": "index.js", 7 | "private": true, 8 | "scripts": { 9 | "start": "concurrently -c \"auto\" \"pnpm:watch:renderer\" \"pnpm:dev\"", 10 | "start:prod": "concurrently -c \"auto\" \"pnpm:watch:renderer\" \"pnpm:watch\" \"sleep 5 && pnpm preview\"", 11 | "dev": "vite --open --host", 12 | "build": "vite build", 13 | "watch": "vite build --watch", 14 | "watch-all": "concurrently -c \"auto\" \"pnpm:watch:renderer\" \"pnpm:watch\"", 15 | "preview": "vite preview --host --open", 16 | "preview:automation": "vite preview", 17 | "build:renderer": "cd .. && pnpm build", 18 | "watch:renderer": "cd .. && pnpm watch" 19 | }, 20 | "author": "Frank Weindel", 21 | "license": "Apache-2.0", 22 | "dependencies": { 23 | "@lightningjs/renderer": "link:..", 24 | "@stdlib/random-base-mt19937": "^0.2.1" 25 | }, 26 | "devDependencies": { 27 | "@vitejs/plugin-legacy": "^5.4.2", 28 | "vite": "^5.4.8", 29 | "whatwg-fetch": "^3.6.2" 30 | }, 31 | "engines": { 32 | "npm": "please-use-pnpm" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/public/fonts/NotoSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/NotoSans-Bold.ttf -------------------------------------------------------------------------------- /examples/public/fonts/NotoSans-Regular.ssdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/NotoSans-Regular.ssdf.png -------------------------------------------------------------------------------- /examples/public/fonts/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /examples/public/fonts/Ubuntu-Bold.msdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/Ubuntu-Bold.msdf.png -------------------------------------------------------------------------------- /examples/public/fonts/Ubuntu-Bold.ssdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/Ubuntu-Bold.ssdf.png -------------------------------------------------------------------------------- /examples/public/fonts/Ubuntu-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/Ubuntu-Bold.ttf -------------------------------------------------------------------------------- /examples/public/fonts/Ubuntu-Regular.msdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/Ubuntu-Regular.msdf.png -------------------------------------------------------------------------------- /examples/public/fonts/Ubuntu-Regular.ssdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/Ubuntu-Regular.ssdf.png -------------------------------------------------------------------------------- /examples/public/fonts/Ubuntu-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/examples/public/fonts/Ubuntu-Regular.ttf -------------------------------------------------------------------------------- /examples/tests/alpha.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 21 | 22 | export async function automation(settings: ExampleSettings) { 23 | // Snapshot single page 24 | await test(settings); 25 | await settings.snapshot(); 26 | } 27 | 28 | export default async function test({ renderer, testRoot }: ExampleSettings) { 29 | const parent = renderer.createNode({ 30 | x: 200, 31 | y: 240, 32 | width: 500, 33 | height: 500, 34 | color: 0x000000ff, 35 | parent: testRoot, 36 | zIndex: 0, 37 | zIndexLocked: 1, 38 | alpha: 0.5, 39 | }); 40 | 41 | const child = renderer.createNode({ 42 | x: 800, 43 | y: 0, 44 | width: 500, 45 | height: 500, 46 | color: 0xff0000ff, 47 | parent, 48 | zIndex: 12, 49 | alpha: 1, 50 | }); 51 | 52 | console.log('ready!'); 53 | } 54 | -------------------------------------------------------------------------------- /examples/tests/child-positioning.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 21 | 22 | export default async function ({ renderer, testRoot }: ExampleSettings) { 23 | const rand = (min: number, max: number) => { 24 | return Math.random() * (max - min) + min; 25 | }; 26 | 27 | new Array(16).fill(0).forEach((el, idx) => { 28 | const pivot = Math.random(); 29 | 30 | const node = renderer.createNode({ 31 | x: (idx % 5) * 250 + 100, 32 | y: Math.floor(idx / 5) * 250 + 100, 33 | width: rand(50, 120), 34 | height: rand(50, 120), 35 | color: 0x0000ffaa, 36 | parent: testRoot, 37 | }); 38 | 39 | const R1 = renderer.createNode({ 40 | x: 10, 41 | y: 10, 42 | width: 20, 43 | height: 20, 44 | color: 0xffffffff, 45 | parent: node, 46 | scale: 1, 47 | }); 48 | 49 | const R3 = renderer.createNode({ 50 | x: 40, 51 | y: 40, 52 | width: 10, 53 | height: 10, 54 | color: 0xffffffff, 55 | parent: node, 56 | scale: 1, 57 | rotation: 0.5, 58 | }); 59 | 60 | setTimeout(() => { 61 | // node.rotation = 0.9; 62 | node 63 | .animate( 64 | { 65 | rotation: Math.PI * 2, 66 | x: rand(-500, 1700), 67 | y: rand(-500, 900), 68 | scale: 2, 69 | }, 70 | { 71 | duration: 4000, 72 | loop: true, 73 | easing: 'cubic-bezier(0.5, 0.5, 0.5, 0.5)', 74 | }, 75 | ) 76 | .start(); 77 | }, 1400); 78 | }); 79 | } 80 | -------------------------------------------------------------------------------- /examples/tests/clipping-mutations.ts: -------------------------------------------------------------------------------- 1 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 2 | import robotImg from '../assets/robot/robot.png'; 3 | 4 | export async function automation(settings: ExampleSettings) { 5 | const next = await test(settings); 6 | // i = 0 7 | await settings.snapshot(); 8 | next(); 9 | // i = 1 10 | await settings.snapshot(); 11 | next(); 12 | // i = 2 13 | await settings.snapshot(); 14 | } 15 | 16 | /** 17 | * Tests that the clipping rect is updated correctly when a parent node with 18 | * clipping set is moved. 19 | * 20 | * Use the 'right arrow' key to move the clipping parent around. 21 | * 22 | * @param settings 23 | * @returns 24 | */ 25 | export default async function test(settings: ExampleSettings) { 26 | const { renderer, testRoot } = settings; 27 | 28 | // Set a smaller snapshot area 29 | testRoot.width = 200; 30 | testRoot.height = 200; 31 | testRoot.color = 0xffffffff; 32 | 33 | const clippedContainer = renderer.createNode({ 34 | x: 0, 35 | y: 0, 36 | width: testRoot.width / 2, 37 | height: testRoot.height / 2, 38 | parent: settings.testRoot, 39 | color: 0x00ffffff, 40 | clipping: true, 41 | }); 42 | 43 | renderer.createNode({ 44 | x: -testRoot.width / 4, 45 | y: -testRoot.height / 4, 46 | width: testRoot.width, 47 | height: testRoot.height, 48 | scale: 0.9, 49 | parent: clippedContainer, 50 | src: robotImg, 51 | }); 52 | 53 | let i = 0; 54 | const MAX_I = 2; 55 | function next() { 56 | i++; 57 | if (i > MAX_I) { 58 | i = 0; 59 | } 60 | if (i === 0) { 61 | clippedContainer.x = 0; 62 | clippedContainer.y = 0; 63 | } else if (i === 1) { 64 | clippedContainer.x = testRoot.width / 4; 65 | } else if (i === 2) { 66 | clippedContainer.x = testRoot.width / 2; 67 | clippedContainer.y = testRoot.height / 2; 68 | } 69 | } 70 | 71 | window.addEventListener('keydown', (event) => { 72 | // When right arrow is pressed, call next 73 | if (event.key === 'ArrowRight') { 74 | next(); 75 | } 76 | }); 77 | 78 | return next; 79 | } 80 | -------------------------------------------------------------------------------- /examples/tests/gradient.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 21 | 22 | export default async function ({ renderer, testRoot }: ExampleSettings) { 23 | const elements = [ 24 | 'colorTl', 25 | 'colorTr', 26 | 'colorBl', 27 | 'colorBr', 28 | 'colorTop', 29 | 'colorBottom', 30 | 'colorLeft', 31 | 'colorRight', 32 | 'color', 33 | ]; 34 | 35 | const nodes = elements.map((element, idx) => { 36 | return renderer.createNode({ 37 | x: (idx % 4) * 300 + 100, 38 | y: Math.floor(idx / 4) * 300 + 100, 39 | width: 250, 40 | height: 250, 41 | color: 0x000000ff, 42 | [element]: 0xff0000ff, 43 | parent: testRoot, 44 | }); 45 | }); 46 | 47 | setTimeout(() => { 48 | nodes.forEach((node, idx) => { 49 | node 50 | .animate( 51 | { 52 | [elements[idx] ?? 'color']: 0x00ff00ff, 53 | }, 54 | { 55 | duration: 1000, 56 | }, 57 | ) 58 | .start(); 59 | }); 60 | }, 2000); 61 | /* 62 | * End: Sprite Map Demo 63 | */ 64 | console.log('ready!'); 65 | } 66 | -------------------------------------------------------------------------------- /examples/tests/no-rtt.ts: -------------------------------------------------------------------------------- 1 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 2 | import test from './alpha-blending.js'; 3 | interface AnimationExampleSettings { 4 | duration: number; 5 | easing: string; 6 | delay: number; 7 | loop: boolean; 8 | stopMethod: 'reverse' | 'reset' | false; 9 | } 10 | 11 | const animationSettings: Partial = { 12 | duration: 14000, 13 | delay: 400, 14 | loop: true, 15 | stopMethod: 'reverse', 16 | easing: 'ease-in-out-back', 17 | }; 18 | 19 | export default async function ({ renderer, testRoot }: ExampleSettings) { 20 | const node = renderer.createNode({ 21 | x: 0, 22 | y: 0, 23 | width: 1920, 24 | height: 1080, 25 | color: 0x000000ff, 26 | parent: testRoot, 27 | }); 28 | const clippingNode = renderer.createNode({ 29 | x: 0, 30 | y: 0, 31 | width: 1920, 32 | height: 1080, 33 | parent: node, 34 | clipping: true, 35 | color: 0x00000000, 36 | }); 37 | 38 | const rootRenderToTextureNode = renderer.createNode({ 39 | x: 0, 40 | y: 0, 41 | width: 1920, 42 | height: 1080, 43 | parent: clippingNode, 44 | rtt: false, 45 | zIndex: 5, 46 | colorTop: 0xc0ffee00, 47 | colorBottom: 0xbada5500, 48 | }); 49 | 50 | new Array(2000).fill(0).forEach((_, i) => { 51 | const image = i % 105; 52 | const a = renderer.createNode({ 53 | parent: rootRenderToTextureNode, 54 | x: (i % 15) * 120 + 120, 55 | y: Math.floor(i / 15) * 120 + 150, 56 | width: 120, 57 | height: 120, 58 | scale: 0.85, 59 | // src: '../assets/rocko.png', 60 | src: `https://picsum.photos/id/${image + 30}/120/120`, 61 | }); 62 | 63 | const animation = a.animate( 64 | { 65 | y: Math.floor(i / 15) * 120 - 5000, 66 | }, 67 | animationSettings, 68 | ); 69 | 70 | animation.start(); 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /examples/tests/rtt-nested-clipping.ts: -------------------------------------------------------------------------------- 1 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 2 | import rocko from '../assets/rocko.png'; 3 | 4 | export default async function test({ renderer, testRoot }: ExampleSettings) { 5 | const node = renderer.createNode({ 6 | x: 0, 7 | y: 0, 8 | width: 1920, 9 | height: 1080, 10 | color: 0x000000ff, 11 | parent: testRoot, 12 | }); 13 | 14 | // RTT Node 1 15 | const rttNode = renderer.createNode({ 16 | x: 100, 17 | y: 200, 18 | width: 400, 19 | height: 400, 20 | parent: node, 21 | rtt: true, 22 | zIndex: 5, 23 | colorTop: 0xfff00fff, 24 | colorBottom: 0x00ffffff, 25 | }); 26 | 27 | const rect = renderer.createNode({ 28 | x: 0, 29 | y: 0, 30 | width: 300, 31 | height: 300, 32 | parent: rttNode, 33 | clipping: true, 34 | color: 0xff0000ff, 35 | }); 36 | 37 | renderer.createTextNode({ 38 | x: 0, 39 | y: 0, 40 | text: 'Render to texture', 41 | parent: rttNode, 42 | fontSize: 48, 43 | color: 0xffffffff, 44 | fontFamily: 'Ubuntu', 45 | }); 46 | 47 | renderer.createNode({ 48 | x: 50, 49 | y: 100, 50 | width: 600, 51 | height: 600, 52 | parent: rttNode, 53 | src: rocko, 54 | }); 55 | 56 | window.addEventListener('keydown', (e) => { 57 | if (e.key === 's') { 58 | // rect.clipping = !rect.clipping; 59 | rect 60 | .animate( 61 | { 62 | x: 100, //going to render out of bounds as well 63 | }, 64 | { 65 | duration: 3000, 66 | easing: 'ease-out', 67 | loop: true, 68 | stopMethod: 'reverse', 69 | }, 70 | ) 71 | .start(); 72 | } 73 | }); 74 | 75 | // Define the page function to configure different test scenarios 76 | } 77 | -------------------------------------------------------------------------------- /examples/tests/rtt.ts: -------------------------------------------------------------------------------- 1 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 2 | import test from './alpha-blending.js'; 3 | interface AnimationExampleSettings { 4 | duration: number; 5 | easing: string; 6 | delay: number; 7 | loop: boolean; 8 | stopMethod: 'reverse' | 'reset' | false; 9 | } 10 | 11 | const animationSettings: Partial = { 12 | duration: 14000, 13 | delay: 400, 14 | loop: true, 15 | stopMethod: 'reverse', 16 | easing: 'ease-in-out-back', 17 | }; 18 | 19 | const randomColor = () => { 20 | const randomInt = Math.floor(Math.random() * Math.pow(2, 32)); 21 | const hexString = randomInt.toString(16).padStart(8, '0'); 22 | return parseInt(hexString, 16); 23 | }; 24 | 25 | const degToRad = (deg: number) => { 26 | return (Math.PI / 180) * deg; 27 | }; 28 | 29 | export default async function ({ renderer, testRoot }: ExampleSettings) { 30 | const node = renderer.createNode({ 31 | x: 0, 32 | y: 0, 33 | width: 1920, 34 | height: 1080, 35 | color: 0x000000ff, 36 | parent: testRoot, 37 | }); 38 | 39 | const rootRenderToTextureNode = renderer.createNode({ 40 | x: 0, 41 | y: 0, 42 | width: 1920, 43 | height: 1080, 44 | parent: node, 45 | rtt: true, 46 | zIndex: 5, 47 | colorTop: 0xc0ffeeff, 48 | colorBottom: 0xbada55ff, 49 | }); 50 | 51 | new Array(105).fill(0).forEach((_, i) => { 52 | const a = renderer.createNode({ 53 | parent: rootRenderToTextureNode, 54 | x: (i % 15) * 120 + 120, 55 | y: Math.floor(i / 15) * 120 + 150, 56 | width: 120, 57 | height: 120, 58 | scale: 1, 59 | // src: '../assets/rocko.png', 60 | src: `https://picsum.photos/id/${i + 30}/120/120`, 61 | }); 62 | }); 63 | 64 | new Array(20).fill(0).forEach((_, i) => { 65 | const a = renderer.createNode({ 66 | x: (i % 1) * 1920, 67 | y: Math.floor(i / 1) * 800, 68 | width: 1920, 69 | height: 1080, 70 | parent: testRoot, 71 | alpha: 1, 72 | color: 0xffffffff, 73 | // Copy source texture from rootRenderToTextureNode 74 | texture: rootRenderToTextureNode.texture, 75 | }); 76 | 77 | const animation = a.animate( 78 | { 79 | y: Math.floor(i / 1) * 800 - 15000, 80 | }, 81 | animationSettings, 82 | ); 83 | animation.start(); 84 | }); 85 | 86 | setTimeout(() => { 87 | rootRenderToTextureNode.alpha = 0; 88 | }, 2000); 89 | } 90 | -------------------------------------------------------------------------------- /examples/tests/shader-animation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 21 | 22 | export async function automation(settings: ExampleSettings) { 23 | // Snapshot single page 24 | await test(settings); 25 | // await settings.snapshot(); 26 | } 27 | 28 | export default async function test({ 29 | renderer, 30 | testRoot, 31 | snapshot, 32 | }: ExampleSettings) { 33 | const degToRad = (deg: number) => { 34 | return (Math.PI / 180) * deg; 35 | }; 36 | 37 | const nodeSize = { 38 | width: 300, 39 | height: 300, 40 | }; 41 | 42 | const t1 = renderer.createNode({ 43 | ...nodeSize, 44 | x: 90, 45 | y: 90, 46 | color: 0xff0000ff, 47 | shader: renderer.createShader('Rounded', { 48 | radius: 100, 49 | }), 50 | parent: testRoot, 51 | }); 52 | 53 | const t1Radius = renderer.createTextNode({ 54 | mountX: 1, 55 | x: testRoot.width - 90, 56 | y: 90, 57 | fontSize: 40, 58 | fontFamily: 'Ubuntu', 59 | text: 'radius: 100', 60 | parent: testRoot, 61 | color: 0xffffffff, 62 | }); 63 | 64 | await snapshot({ name: 'startup' }); 65 | 66 | const shaderAnimation = t1.animate( 67 | { 68 | x: 1140, 69 | shaderProps: { 70 | radius: 150, 71 | }, 72 | }, 73 | { 74 | duration: 500, 75 | }, 76 | ); 77 | // shaderAnimation.start(); 78 | // await shaderAnimation.waitUntilStopped(); 79 | // t1Radius.text = 'radius: ' + t1.shader.props!.radius.toString(); 80 | // await snapshot({ name: 'animation1' }); 81 | } 82 | -------------------------------------------------------------------------------- /examples/tests/shader-hole-punch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 19 | 20 | export async function automation(settings: ExampleSettings) { 21 | // Snapshot single page 22 | await test(settings); 23 | await settings.snapshot(); 24 | } 25 | 26 | export default async function test({ renderer, testRoot }: ExampleSettings) { 27 | const RedRect = renderer.createNode({ 28 | x: 20, 29 | y: 20, 30 | width: 600, 31 | height: 400, 32 | color: 0xff0000ff, 33 | shader: renderer.createShader('HolePunch'), 34 | parent: testRoot, 35 | }); 36 | 37 | const RedRect2 = renderer.createNode({ 38 | x: 720, 39 | y: 20, 40 | width: 600, 41 | height: 400, 42 | color: 0xff0000ff, 43 | shader: renderer.createShader('HolePunch', { 44 | x: 100, 45 | y: 100, 46 | width: 100, 47 | height: 100, 48 | radius: 10, 49 | }), 50 | parent: testRoot, 51 | }); 52 | 53 | const GreenRect = renderer.createNode({ 54 | x: 20, 55 | y: 520, 56 | width: 600, 57 | height: 400, 58 | color: 0x00ff00ff, 59 | shader: renderer.createShader('HolePunch', { 60 | x: 100, 61 | y: 100, 62 | width: 200, 63 | height: 150, 64 | radius: 10, 65 | }), 66 | parent: testRoot, 67 | }); 68 | 69 | const GreenRect2 = renderer.createNode({ 70 | x: 720, 71 | y: 520, 72 | width: 600, 73 | height: 400, 74 | color: 0x00ff00ff, 75 | shader: renderer.createShader('HolePunch', { 76 | x: 270, 77 | y: 200, 78 | width: 225, 79 | height: 150, 80 | radius: [50, 20, 30], 81 | }), 82 | parent: testRoot, 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /examples/tests/shader-shadow.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 19 | 20 | export async function automation(settings: ExampleSettings) { 21 | // Snapshot single page 22 | await test(settings); 23 | await settings.snapshot(); 24 | } 25 | 26 | export default async function test({ renderer, testRoot }: ExampleSettings) { 27 | const node = renderer.createNode({ 28 | x: 0, 29 | y: 0, 30 | width: 1920, 31 | height: 1080, 32 | color: 0xffffffff, 33 | parent: testRoot, 34 | }); 35 | 36 | renderer.createNode({ 37 | x: 300, 38 | y: 300, 39 | mount: 0.5, 40 | width: 250, 41 | height: 250, 42 | color: 0xff00ffff, 43 | shader: renderer.createShader('Shadow', { 44 | x: 50, 45 | spread: 50, 46 | blur: 100, 47 | }), 48 | parent: node, 49 | }); 50 | 51 | renderer.createNode({ 52 | x: 700, 53 | y: 300, 54 | mount: 0.5, 55 | width: 250, 56 | height: 250, 57 | color: 0xff00ffff, 58 | shader: renderer.createShader('RoundedWithShadow', { 59 | radius: 10, 60 | 'shadow-x': 50, 61 | 'shadow-spread': 50, 62 | 'shadow-blur': 100, 63 | }), 64 | parent: node, 65 | }); 66 | 67 | renderer.createNode({ 68 | x: 1100, 69 | y: 300, 70 | mount: 0.5, 71 | width: 250, 72 | height: 250, 73 | color: 0xff00ffff, 74 | shader: renderer.createShader('RoundedWithBorderAndShadow', { 75 | radius: 10, 76 | 'shadow-x': 50, 77 | 'shadow-spread': 50, 78 | 'shadow-blur': 100, 79 | 'border-width': 20, 80 | }), 81 | parent: node, 82 | }); 83 | } 84 | -------------------------------------------------------------------------------- /examples/tests/stress-images.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 19 | 20 | export default async function ({ renderer, testRoot }: ExampleSettings) { 21 | const screenWidth = 1920; 22 | const screenHeight = 1080; 23 | const totalImages = 1000; 24 | 25 | // Calculate the grid dimensions for square images 26 | const gridSize = Math.ceil(Math.sqrt(totalImages)); // Approximate grid size 27 | const imageSize = Math.floor( 28 | Math.min(screenWidth / gridSize, screenHeight / gridSize), 29 | ); // Square size 30 | 31 | // Create a root node for the grid 32 | const gridNode = renderer.createNode({ 33 | x: 0, 34 | y: 0, 35 | width: screenWidth, 36 | height: screenHeight, 37 | parent: testRoot, 38 | }); 39 | 40 | // Create and position images in the grid 41 | new Array(totalImages).fill(0).forEach((_, i) => { 42 | const x = (i % gridSize) * imageSize; 43 | const y = Math.floor(i / gridSize) * imageSize; 44 | 45 | renderer.createNode({ 46 | parent: gridNode, 47 | x, 48 | y, 49 | width: imageSize, 50 | height: imageSize, 51 | src: `https://picsum.photos/id/${i}/${imageSize}/${imageSize}`, // Random images 52 | }); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /examples/tests/stress-textures.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 19 | 20 | export const Colors = { 21 | Black: 0x000000ff, 22 | Red: 0xff0000ff, 23 | Green: 0x00ff00ff, 24 | Blue: 0x0000ffff, 25 | Magenta: 0xff00ffff, 26 | Gray: 0x7f7f7fff, 27 | White: 0xffffffff, 28 | }; 29 | 30 | export default async function ({ renderer, testRoot }: ExampleSettings) { 31 | const screenWidth = 1920; 32 | const screenHeight = 1080; 33 | const totalImages = 1000; 34 | 35 | // Calculate the grid dimensions for square images 36 | const gridSize = Math.ceil(Math.sqrt(totalImages)); // Approximate grid size 37 | const imageSize = Math.floor( 38 | Math.min(screenWidth / gridSize, screenHeight / gridSize), 39 | ); // Square size 40 | 41 | // Create a root node for the grid 42 | const gridNode = renderer.createNode({ 43 | x: 0, 44 | y: 0, 45 | width: screenWidth, 46 | height: screenHeight, 47 | parent: testRoot, 48 | }); 49 | 50 | // Create and position images in the grid 51 | new Array(totalImages).fill(0).forEach((_, i) => { 52 | const x = (i % gridSize) * imageSize; 53 | const y = Math.floor(i / gridSize) * imageSize; 54 | 55 | // pick a random color from Colors 56 | const clr = 57 | Object.values(Colors)[ 58 | Math.floor(Math.random() * Object.keys(Colors).length) 59 | ]; 60 | 61 | renderer.createNode({ 62 | parent: gridNode, 63 | x, 64 | y, 65 | width: imageSize, 66 | height: imageSize, 67 | color: clr, 68 | }); 69 | }); 70 | } 71 | -------------------------------------------------------------------------------- /examples/tests/text-ssdf.ts: -------------------------------------------------------------------------------- 1 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 2 | 3 | export async function automation(settings: ExampleSettings) { 4 | await test(settings); 5 | await settings.snapshot(); 6 | } 7 | 8 | /** 9 | * Tests that Single-Channel Signed Distance Field (SSDF) fonts are rendered 10 | * correctly. 11 | * 12 | * Text that is thinner than the certified snapshot may indicate that the 13 | * SSDF font atlas texture was premultiplied before being uploaded to the GPU. 14 | * 15 | * @param settings 16 | * @returns 17 | */ 18 | export default async function test(settings: ExampleSettings) { 19 | const { renderer, testRoot } = settings; 20 | 21 | // Set a smaller snapshot area 22 | testRoot.width = 200; 23 | testRoot.height = 200; 24 | testRoot.color = 0xffffffff; 25 | 26 | renderer.createTextNode({ 27 | text: 'SSDF', 28 | color: 0x000000ff, 29 | fontFamily: 'Ubuntu-ssdf', 30 | parent: testRoot, 31 | fontSize: 80, 32 | lineHeight: 80 * 1.2, 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /examples/tests/texture-autosize.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 19 | import robotImg from '../assets/robot/robot.png'; 20 | import { waitForLoadedDimensions } from '../common/utils.js'; 21 | 22 | export async function automation(settings: ExampleSettings) { 23 | await test(settings); 24 | await settings.snapshot(); 25 | } 26 | 27 | /** 28 | * Tests that text nodes with different contain settings and text renderers 29 | * are displayed correctly. 30 | * 31 | * Press the right arrow key to cycle through the different settings when 32 | * running in the browser. 33 | * 34 | * @param settings 35 | * @returns 36 | */ 37 | export default async function test(settings: ExampleSettings) { 38 | const { renderer, testRoot } = settings; 39 | 40 | // Set a smaller snapshot area 41 | testRoot.width = 200; 42 | testRoot.height = 250; 43 | testRoot.color = 0xffffffff; 44 | 45 | const image = renderer.createNode({ 46 | mount: 0.5, 47 | x: testRoot.width / 2, 48 | y: testRoot.height / 4, 49 | autosize: true, 50 | src: robotImg, 51 | parent: testRoot, 52 | }); 53 | 54 | const dimensions = await waitForLoadedDimensions(image); 55 | 56 | const dimensionsMatch = 57 | dimensions.width === image.width && dimensions.height === image.height; 58 | 59 | renderer.createTextNode({ 60 | mountX: 0.5, 61 | mountY: 1, 62 | x: testRoot.width / 2, 63 | y: testRoot.height, 64 | textAlign: 'center', 65 | text: dimensionsMatch ? 'Autosize\nSuccess' : 'Autosize\nFailure', 66 | color: dimensionsMatch ? 0x00ff00ff : 0xff0000ff, 67 | fontSize: 50, 68 | fontFamily: 'Ubuntu', 69 | parent: testRoot, 70 | }); 71 | } 72 | -------------------------------------------------------------------------------- /examples/tests/tx-compression.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 21 | 22 | export default async function ({ renderer, testRoot }: ExampleSettings) { 23 | renderer.createTextNode({ 24 | x: 100, 25 | y: 100, 26 | color: 0xffffffff, 27 | alpha: 1.0, 28 | text: 'etc1 compression in .pvr', 29 | fontFamily: 'Ubuntu', 30 | fontSize: 30, 31 | parent: testRoot, 32 | }); 33 | 34 | renderer.createNode({ 35 | x: 100, 36 | y: 170, 37 | width: 550, 38 | height: 550, 39 | src: '../assets/test-etc1.pvr', 40 | parent: testRoot, 41 | }); 42 | 43 | renderer.createTextNode({ 44 | x: 800, 45 | y: 100, 46 | color: 0xffffffff, 47 | alpha: 1.0, 48 | text: 's3tc compression in .ktx', 49 | fontFamily: 'Ubuntu', 50 | fontSize: 30, 51 | parent: testRoot, 52 | }); 53 | 54 | renderer.createNode({ 55 | x: 800, 56 | y: 170, 57 | width: 400, 58 | height: 400, 59 | src: '../assets/test-s3tc.ktx', 60 | parent: testRoot, 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /examples/tests/viewport-strictbounds.ts: -------------------------------------------------------------------------------- 1 | import type { ExampleSettings } from '../common/ExampleSettings.js'; 2 | 3 | export async function automation(settings: ExampleSettings) { 4 | const page = await test(settings); 5 | page(1); 6 | await settings.snapshot(); 7 | 8 | page(2); 9 | await settings.snapshot(); 10 | 11 | page(3); 12 | await settings.snapshot(); 13 | } 14 | 15 | export default async function test({ renderer, testRoot }: ExampleSettings) { 16 | // Create a container node 17 | const containerNode = renderer.createNode({ 18 | x: 10, 19 | y: 100, 20 | width: 1000, 21 | height: 600, 22 | color: 0xff0000ff, // Red 23 | parent: testRoot, 24 | strictBounds: false, 25 | }); 26 | 27 | const status = renderer.createTextNode({ 28 | text: 'Strict Bound: ', 29 | fontSize: 30, 30 | x: 10, 31 | y: 50, 32 | parent: testRoot, 33 | }); 34 | 35 | const amountOfNodes = 11; 36 | const childNodeWidth = 1700 / amountOfNodes; 37 | 38 | // Create 11 child nodes 39 | for (let i = 0; i < amountOfNodes; i++) { 40 | const childNode = renderer.createNode({ 41 | x: i * childNodeWidth + i * 100, 42 | y: 100, 43 | width: childNodeWidth, 44 | height: 300, 45 | color: 0x00ff00ff, // Green 46 | parent: containerNode, 47 | }); 48 | 49 | const nodeTest = renderer.createTextNode({ 50 | x: 10, 51 | y: 130, 52 | text: `Node ${i}`, 53 | color: 0x000000ff, 54 | parent: childNode, 55 | }); 56 | } 57 | 58 | renderer.on('idle', () => { 59 | status.text = 'Strict Bound: ' + String(containerNode.strictBounds); 60 | }); 61 | 62 | window.onkeydown = (e) => { 63 | if (e.key === 'ArrowRight') { 64 | containerNode.x -= 100; 65 | } 66 | 67 | if (e.key === 'ArrowLeft') { 68 | containerNode.x += 100; 69 | } 70 | 71 | if (e.key === ' ') { 72 | containerNode.strictBounds = !containerNode.strictBounds; 73 | } 74 | }; 75 | 76 | const page = (i = 0) => { 77 | switch (i) { 78 | case 1: 79 | containerNode.x = -590; 80 | break; 81 | 82 | case 2: 83 | containerNode.x = -1390; 84 | break; 85 | 86 | case 3: 87 | containerNode.strictBounds = true; 88 | break; 89 | } 90 | }; 91 | 92 | return page; 93 | } 94 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "dist-tsc", 6 | "types": [], 7 | "lib": ["ES2022", "DOM"], 8 | "noEmit": true, 9 | }, 10 | "include": [ 11 | "./**/*.ts", "./common/**/*.ts" 12 | ], 13 | "exclude": ["node_modules", "./**/*.test.ts"], 14 | } 15 | -------------------------------------------------------------------------------- /examples/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /// 21 | // This enables Vite's import.meta augmentations and possibly other things? 22 | -------------------------------------------------------------------------------- /exports/canvas-shaders.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | export * from '../src/core/renderers/canvas/CanvasShaderNode.js'; 19 | 20 | export { Rounded } from '../src/core/shaders/canvas/Rounded.js'; 21 | export { RoundedWithBorder } from '../src/core/shaders/canvas/RoundedWithBorder.js'; 22 | export { RoundedWithBorderAndShadow } from '../src/core/shaders/canvas/RoundedWithBorderAndShadow.js'; 23 | export { RoundedWithShadow } from '../src/core/shaders/canvas/RoundedWithShadow.js'; 24 | export { Border } from '../src/core/shaders/canvas/Border.js'; 25 | export { Shadow } from '../src/core/shaders/canvas/Shadow.js'; 26 | export { HolePunch } from '../src/core/shaders/canvas/HolePunch.js'; 27 | export { LinearGradient } from '../src/core/shaders/canvas/LinearGradient.js'; 28 | export { RadialGradient } from '../src/core/shaders/canvas/RadialGradient.js'; 29 | -------------------------------------------------------------------------------- /exports/canvas.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | /** 20 | * Canvas Text Renderer 21 | * 22 | * @remarks 23 | * This module exports the Canvas Text Renderer for the Lightning 3 Renderer. 24 | * The Canvas Text Renderer is used to render text using the Canvas API, 25 | * this is slightly less performant than the SDF Text Renderer. However 26 | * the Canvas Text Renderer is more widely supported on older devices. 27 | * 28 | * You can import the exports from this module like so: 29 | * ```ts 30 | * import { CanvasTextRenderer } from '@lightning/renderer'; 31 | * ``` 32 | * 33 | * @module Canvas 34 | * 35 | * @packageDocumentation 36 | */ 37 | 38 | export { CanvasTextRenderer } from '../src/core/text-rendering/renderers/CanvasTextRenderer.js'; 39 | export { CanvasRenderer } from '../src/core/renderers/canvas/CanvasRenderer.js'; 40 | export { CanvasTexture } from '../src/core/renderers/canvas/CanvasTexture.js'; 41 | export * from '../src/core/renderers/canvas/CanvasShaderNode.js'; 42 | /** 43 | * @deprecated Use CanvasRenderer. 44 | */ 45 | export { CanvasRenderer as CanvasCoreRenderer } from '../src/core/renderers/canvas/CanvasRenderer.js'; 46 | -------------------------------------------------------------------------------- /exports/inspector.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @module Inspector 22 | */ 23 | 24 | export { Inspector } from '../src/main-api/Inspector.js'; 25 | -------------------------------------------------------------------------------- /exports/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | /** 20 | * Auxiliary Utilities 21 | * 22 | * @remarks 23 | * This module exports the a set of utilities that may be optionally used by 24 | * developers using the Lightning 3 Renderer. 25 | * 26 | * You can import the exports from this module like so: 27 | * ```ts 28 | * import { assertTruthy } from '@lightning/renderer'; 29 | * ``` 30 | * 31 | * @internalRemarks 32 | * Exports in here should be chosen wisely, as they will be exposed to 33 | * directly developers. 34 | * 35 | * They should be general utilities that are NOT directly coupled to the 36 | * Lightning Renderer, and not specific to any particular platform. 37 | * 38 | * @packageDocumentation 39 | * 40 | * @module Utils 41 | */ 42 | export { 43 | assertTruthy, 44 | mergeColorAlpha, 45 | deg2Rad, 46 | mergeColorProgress, 47 | } from '../src/utils.js'; 48 | export { getNormalizedRgbaComponents } from '../src/core/lib/utils.js'; 49 | export { getTimingFunction } from '../src/core/utils.js'; 50 | export { EventEmitter } from '../src/common/EventEmitter.js'; 51 | -------------------------------------------------------------------------------- /exports/webgl-shaders.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | export * from '../src/core/renderers/webgl/WebGlShaderNode.js'; 18 | 19 | export { Rounded } from '../src/core/shaders/webgl/Rounded.js'; 20 | export { RoundedWithBorder } from '../src/core/shaders/webgl/RoundedWithBorder.js'; 21 | export { RoundedWithBorderAndShadow } from '../src/core/shaders/webgl/RoundedWithBorderAndShadow.js'; 22 | export { RoundedWithShadow } from '../src/core/shaders/webgl/RoundedWithShadow.js'; 23 | export { Border } from '../src/core/shaders/webgl/Border.js'; 24 | export { Shadow } from '../src/core/shaders/webgl/Shadow.js'; 25 | export { HolePunch } from '../src/core/shaders/webgl/HolePunch.js'; 26 | export { LinearGradient } from '../src/core/shaders/webgl/LinearGradient.js'; 27 | export { RadialGradient } from '../src/core/shaders/webgl/RadialGradient.js'; 28 | export { Default } from '../src/core/shaders/webgl/Default.js'; 29 | -------------------------------------------------------------------------------- /exports/webgl.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * SDF Font renderer 22 | * 23 | * @remarks 24 | * This module exports the SDF Font renderer for the Lightning 3 Renderer. 25 | * The SDF Font renderer is used to render text using Single-Channel Signed 26 | * Distance Field (SSDF) fonts or Multi-Channel Signed Distance Field (MSDF) 27 | * fonts. The SDF font renderer is used to render text in a way that is 28 | * optimized for GPU rendering. 29 | * 30 | * You can import the exports from this module like so: 31 | * ```ts 32 | * import { SdfTextRenderer } from '@lightning/renderer'; 33 | * ``` 34 | * 35 | * @packageDocumentation 36 | */ 37 | 38 | export { SdfTextRenderer } from '../src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js'; 39 | export { WebGlRenderer } from '../src/core/renderers/webgl/WebGlRenderer.js'; 40 | export { WebGlCtxTexture } from '../src/core/renderers/webgl/WebGlCtxTexture.js'; 41 | 42 | export * from '../src/core/renderers/webgl/WebGlShaderNode.js'; 43 | 44 | /** 45 | * @deprecated Use WebGlRenderer. 46 | */ 47 | export { WebGlRenderer as WebGlCoreRenderer } from '../src/core/renderers/webgl/WebGlRenderer.js'; 48 | export { WebGlRenderer as WebGlCoreCtxTexture } from '../src/core/renderers/webgl/WebGlRenderer.js'; 49 | 50 | export * as shaders from './webgl-shaders.js'; 51 | -------------------------------------------------------------------------------- /performance/.gitignore: -------------------------------------------------------------------------------- 1 | baseline.json 2 | -------------------------------------------------------------------------------- /performance/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/performance/bun.lockb -------------------------------------------------------------------------------- /performance/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "performance", 3 | "version": "0.0.1", 4 | "author": "", 5 | "main": "index.js", 6 | "description": "", 7 | "keywords": [], 8 | "license": "ISC", 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "dependencies": { 13 | "sinon": "^18.0.0", 14 | "tinybench": "^2.9.0", 15 | "ts-sinon": "^2.0.2" 16 | }, 17 | "devDependencies": { 18 | "@types/bun": "^1.1.8" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /performance/readme.md: -------------------------------------------------------------------------------- 1 | # Performance Benchmark Utility 2 | 3 | This utility allows you to run performance benchmarks for various components of the project. It provides a simple way to execute tests, compare results against a baseline, and create new baselines. 4 | 5 | ## Usage 6 | 7 | ### Running Tests 8 | 9 | To run all tests: 10 | `bun run performance/index.ts` 11 | 12 | To run a specific test: 13 | `bun run performance/index.ts -t ` 14 | 15 | ### Creating a New Baseline 16 | 17 | To create a new baseline: 18 | `bun run performance/index.ts -c` 19 | 20 | Results are saved to `performance/baseline.json` and will be automatically used for future comparisons. 21 | 22 | ## Warning 23 | 24 | Use with care, these are limited benchmarks and highligh a specific case of the code, and should be used as approximations to see if changes have improved performance. Use them in combination with other tests such as rendering benchmarks to get a more complete picture. 25 | 26 | Don't tunnel on performance, and use these results as a tool to guide your development. 27 | -------------------------------------------------------------------------------- /performance/src/WebGlContextWrapper.ts: -------------------------------------------------------------------------------- 1 | // Tree - mimic a rendering tree with core nodes and animations 2 | // test modules 3 | import { Bench } from 'tinybench'; 4 | // import * as sinon from 'ts-sinon'; 5 | import { performance } from 'perf_hooks'; 6 | import { type IndividualTestResult } from './utils/types.js'; 7 | 8 | import { compareArrays } from '../../src/core/lib/WebGlContextWrapper.js'; 9 | 10 | const bench = new Bench(); 11 | 12 | // Grab command line arguments 13 | const args = process.argv.slice(2); 14 | const isTestRunnerTest = args.includes('--testRunner'); 15 | 16 | // generate large array with random values 17 | const largeArray = new Array(1000).fill(0).map(() => Math.random()); 18 | const largeArrayCopy = largeArray.slice(); 19 | 20 | // change random value in at middle index 21 | const middleIndex = Math.floor(largeArray.length / 2); 22 | largeArrayCopy[middleIndex] = Math.random(); 23 | 24 | bench 25 | .add('Arrays', () => { 26 | compareArrays([1, 2, 3], [1, 2, 3]); 27 | }) 28 | .add('Large Arrays', () => { 29 | compareArrays(new Array(1000).fill(1), new Array(1000).fill(1)); 30 | }) 31 | .add('Large Arrays diff vals', () => { 32 | compareArrays(new Array(1000).fill(1), new Array(1000).fill(2)); 33 | }) 34 | .add('Large Arrays diff lengths', () => { 35 | compareArrays(new Array(1000).fill(1), new Array(1001).fill(1)); 36 | }) 37 | .add('Large Array random diff', () => { 38 | compareArrays(largeArray, largeArrayCopy); 39 | }); 40 | 41 | await bench.warmup(); 42 | await bench.run(); 43 | 44 | if (!isTestRunnerTest) { 45 | console.table(bench.table()); 46 | } 47 | 48 | if (isTestRunnerTest) { 49 | const results: IndividualTestResult[] = []; 50 | 51 | bench.tasks.forEach((task) => { 52 | if (!task.result) { 53 | return; 54 | } 55 | 56 | if (task.result.error) { 57 | return; 58 | } 59 | 60 | results.push({ 61 | name: task.name, 62 | opsPerSecond: task.result.hz, 63 | avgTime: task.result.mean * 1000 * 1000, 64 | margin: task.result.rme, 65 | samples: task.result.samples.length, 66 | }); 67 | }); 68 | 69 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 70 | // @ts-ignore 71 | process.send(results); 72 | } 73 | -------------------------------------------------------------------------------- /performance/src/utils/types.ts: -------------------------------------------------------------------------------- 1 | export interface IndividualTestResult { 2 | name: string; 3 | opsPerSecond: number; 4 | avgTime: number; 5 | margin: number; 6 | samples: number; 7 | } 8 | 9 | export interface TestResult { 10 | name: string; 11 | results: IndividualTestResult[]; 12 | } 13 | -------------------------------------------------------------------------------- /performance/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "types": [], 5 | "lib": ["ES2022"], 6 | "module":"ESNext", 7 | "moduleResolution": "Node" 8 | }, 9 | "include": [ 10 | "./**/*.ts", "../src/**/*.ts" 11 | ], 12 | "exclude": ["node_modules", "./**/*.test.ts"], 13 | } 14 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Comcast Cable Communications Management, LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | # 14 | # SPDX-License-Identifier: Apache-2.0 15 | 16 | packages: 17 | - "examples" 18 | - "visual-regression" 19 | -------------------------------------------------------------------------------- /src/common/IEventEmitter.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | export interface IEventEmitter< 19 | T extends object = { [s: string]: (target: any, data: any) => void }, 20 | > { 21 | on(event: Extract, listener: T[K]): void; 22 | once(event: Extract, listener: T[K]): void; 23 | off(event: Extract, listener: T[K]): void; 24 | emit( 25 | event: Extract, 26 | data: Parameters[1], 27 | ): void; 28 | } 29 | -------------------------------------------------------------------------------- /src/core/animations/AnimationManager.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import { CoreAnimation } from './CoreAnimation.js'; 21 | 22 | export class AnimationManager { 23 | activeAnimations: Set = new Set(); 24 | 25 | registerAnimation(animation: CoreAnimation) { 26 | this.activeAnimations.add(animation); 27 | } 28 | 29 | unregisterAnimation(animation: CoreAnimation) { 30 | this.activeAnimations.delete(animation); 31 | } 32 | 33 | update(dt: number) { 34 | this.activeAnimations.forEach((animation) => { 35 | animation.update(dt); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/core/lib/ContextSpy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * Class that keeps track of the invocations of Context methods when 22 | * the `enableContextSpy` renderer option is enabled. 23 | */ 24 | export class ContextSpy { 25 | private data: Record = {}; 26 | 27 | reset() { 28 | this.data = {}; 29 | } 30 | 31 | increment(name: string) { 32 | if (!this.data[name]) { 33 | this.data[name] = 0; 34 | } 35 | this.data[name]++; 36 | } 37 | 38 | getData() { 39 | return { ...this.data }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/core/lib/RenderCoords.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | export class RenderCoords { 18 | public x1: number; 19 | public y1: number; 20 | public x2: number; 21 | public y2: number; 22 | public x3: number; 23 | public y3: number; 24 | public x4: number; 25 | public y4: number; 26 | 27 | constructor( 28 | x1: number, 29 | y1: number, 30 | x2: number, 31 | y2: number, 32 | x3: number, 33 | y3: number, 34 | x4: number, 35 | y4: number, 36 | ) { 37 | this.x1 = x1; 38 | this.y1 = y1; 39 | this.x2 = x2; 40 | this.y2 = y2; 41 | this.x3 = x3; 42 | this.y3 = y3; 43 | this.x4 = x4; 44 | this.y4 = y4; 45 | } 46 | 47 | static translate( 48 | x1: number, 49 | y1: number, 50 | x2: number, 51 | y2: number, 52 | x3: number, 53 | y3: number, 54 | x4: number, 55 | y4: number, 56 | out?: RenderCoords, 57 | ): RenderCoords { 58 | if (out === undefined) { 59 | return new RenderCoords(x1, y1, x2, y2, x3, y3, x4, y4); 60 | } 61 | out.x1 = x1; 62 | out.y1 = y1; 63 | out.x2 = x2; 64 | out.y2 = y2; 65 | out.x3 = x3; 66 | out.y3 = y3; 67 | out.x4 = x4; 68 | out.y4 = y4; 69 | return out; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/core/lib/textureSvg.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import { assertTruthy } from '../../utils.js'; 21 | import { type TextureData } from '../textures/Texture.js'; 22 | 23 | /** 24 | * Tests if the given location is a SVG 25 | * @param url 26 | * @remarks 27 | * This function is used to determine if the given image url is a SVG 28 | * image 29 | * @returns 30 | */ 31 | export function isSvgImage(url: string): boolean { 32 | return /\.(svg)(\?.*)?$/.test(url); 33 | } 34 | 35 | /** 36 | * Loads a SVG image 37 | * @param url 38 | * @returns 39 | */ 40 | export const loadSvg = ( 41 | url: string, 42 | width: number | null, 43 | height: number | null, 44 | sx: number | null, 45 | sy: number | null, 46 | sw: number | null, 47 | sh: number | null, 48 | ): Promise => { 49 | return new Promise((resolve, reject) => { 50 | const canvas = document.createElement('canvas'); 51 | const ctx = canvas.getContext('2d'); 52 | assertTruthy(ctx); 53 | 54 | ctx.imageSmoothingEnabled = true; 55 | const img = new Image(); 56 | img.onload = () => { 57 | const x = sx ?? 0; 58 | const y = sy ?? 0; 59 | const w = width || img.width; 60 | const h = height || img.height; 61 | 62 | canvas.width = w; 63 | canvas.height = h; 64 | ctx.drawImage(img, 0, 0, w, h); 65 | 66 | resolve({ 67 | data: ctx.getImageData(x, y, sw ?? w, sh ?? h), 68 | premultiplyAlpha: false, 69 | }); 70 | }; 71 | 72 | img.onerror = (err) => { 73 | reject(err); 74 | }; 75 | 76 | img.src = url; 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /src/core/platforms/web/WebPlatform.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from '../Platform.js'; 2 | import type { Stage } from '../../Stage.js'; 3 | 4 | export class WebPlatform extends Platform { 5 | //////////////////////// 6 | // Platform-specific methods 7 | //////////////////////// 8 | 9 | override createCanvas(): HTMLCanvasElement { 10 | const canvas = document.createElement('canvas'); 11 | return canvas; 12 | } 13 | 14 | override getElementById(id: string): HTMLElement | null { 15 | return document.getElementById(id); 16 | } 17 | 18 | //////////////////////// 19 | // Update loop 20 | //////////////////////// 21 | 22 | override startLoop(stage: Stage): void { 23 | let isIdle = false; 24 | const runLoop = () => { 25 | stage.updateFrameTime(); 26 | stage.updateAnimations(); 27 | 28 | if (!stage.hasSceneUpdates()) { 29 | // We still need to calculate the fps else it looks like the app is frozen 30 | stage.calculateFps(); 31 | setTimeout(runLoop, 16.666666666666668); 32 | 33 | if (!isIdle) { 34 | stage.shManager.cleanup(); 35 | stage.eventBus.emit('idle'); 36 | isIdle = true; 37 | } 38 | 39 | if (stage.txMemManager.checkCleanup() === true) { 40 | stage.txMemManager.cleanup(false); 41 | } 42 | 43 | stage.flushFrameEvents(); 44 | return; 45 | } 46 | 47 | isIdle = false; 48 | stage.drawFrame(); 49 | stage.flushFrameEvents(); 50 | requestAnimationFrame(runLoop); 51 | }; 52 | requestAnimationFrame(runLoop); 53 | } 54 | 55 | //////////////////////// 56 | // ImageBitmap 57 | //////////////////////// 58 | 59 | override createImageBitmap( 60 | blob: ImageBitmapSource, 61 | sxOrOptions?: number | ImageBitmapOptions, 62 | sy?: number, 63 | sw?: number, 64 | sh?: number, 65 | options?: ImageBitmapOptions, 66 | ): Promise { 67 | if (typeof sxOrOptions === 'number') { 68 | return createImageBitmap( 69 | blob, 70 | sxOrOptions, 71 | sy ?? 0, 72 | sw ?? 0, 73 | sh ?? 0, 74 | options, 75 | ); 76 | } else { 77 | return createImageBitmap(blob, sxOrOptions); 78 | } 79 | } 80 | 81 | getTimeStamp(): number { 82 | return performance ? performance.now() : Date.now(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/core/renderers/CoreContextTexture.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { TextureMemoryManager } from '../TextureMemoryManager.js'; 21 | import type { Texture } from '../textures/Texture.js'; 22 | 23 | export abstract class CoreContextTexture { 24 | readonly textureSource: Texture; 25 | private memManager: TextureMemoryManager; 26 | public state: 'freed' | 'loading' | 'loaded' | 'failed' = 'freed'; 27 | 28 | constructor(memManager: TextureMemoryManager, textureSource: Texture) { 29 | this.memManager = memManager; 30 | this.textureSource = textureSource; 31 | } 32 | 33 | protected setTextureMemUse(byteSize: number): void { 34 | this.memManager.setTextureMemUse(this.textureSource, byteSize); 35 | } 36 | 37 | abstract load(): void; 38 | abstract free(): void; 39 | 40 | get renderable(): boolean { 41 | return this.textureSource.renderable; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/core/renderers/CoreRenderOp.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | export abstract class CoreRenderOp { 21 | abstract draw(): void; 22 | } 23 | -------------------------------------------------------------------------------- /src/core/renderers/CoreShaderProgram.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | export interface CoreShaderProgram { 21 | attach?: () => void; 22 | detach?: () => void; 23 | } 24 | -------------------------------------------------------------------------------- /src/core/renderers/webgl/WebGlCtxSubTexture.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { Dimensions } from '../../../common/CommonTypes.js'; 21 | import { assertTruthy } from '../../../utils.js'; 22 | import type { TextureMemoryManager } from '../../TextureMemoryManager.js'; 23 | import type { WebGlContextWrapper } from '../../lib/WebGlContextWrapper.js'; 24 | import type { SubTexture } from '../../textures/SubTexture.js'; 25 | import { WebGlCtxTexture } from './WebGlCtxTexture.js'; 26 | 27 | export class WebGlCtxSubTexture extends WebGlCtxTexture { 28 | constructor( 29 | glw: WebGlContextWrapper, 30 | memManager: TextureMemoryManager, 31 | textureSource: SubTexture, 32 | ) { 33 | super(glw, memManager, textureSource); 34 | } 35 | 36 | override async onLoadRequest(): Promise { 37 | const props = (this.textureSource as SubTexture).textureData; 38 | assertTruthy(props, 'SubTexture must have texture data'); 39 | 40 | if (props.data instanceof Uint8Array) { 41 | // its a 1x1 Color Texture 42 | return { width: 1, height: 1 }; 43 | } 44 | 45 | return { 46 | width: props.data?.width || 0, 47 | height: props.data?.height || 0, 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/core/renderers/webgl/internal/BufferCollection.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { AttributeInfo } from './ShaderUtils.js'; 21 | 22 | export interface BufferItem { 23 | buffer: WebGLBuffer; 24 | attributes: Record; 25 | } 26 | 27 | /** 28 | * Represents a collection of WebGL Buffers along with their associated 29 | * vertex attribute formats. 30 | */ 31 | export class BufferCollection { 32 | constructor(readonly config: BufferItem[]) {} 33 | 34 | /** 35 | * Get the WebGLBuffer associated with the given attribute name if it exists. 36 | * 37 | * @param attributeName 38 | * @returns 39 | */ 40 | getBuffer(attributeName: string): WebGLBuffer | undefined { 41 | return this.config.find((item) => item.attributes[attributeName])?.buffer; 42 | } 43 | 44 | /** 45 | * Get the AttributeInfo associated with the given attribute name if it exists. 46 | * 47 | * @param attributeName 48 | * @returns 49 | */ 50 | getAttributeInfo(attributeName: string): AttributeInfo | undefined { 51 | return this.config.find((item) => item.attributes[attributeName]) 52 | ?.attributes[attributeName]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/core/renderers/webgl/internal/WebGlUtils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * Generic WebGL Utility Functions 22 | * 23 | * @remarks 24 | * Nothing here should be coupled to Renderer logic / types. 25 | * 26 | * @param gl 27 | * @returns 28 | */ 29 | export function isWebGl2( 30 | gl: WebGLRenderingContext, 31 | ): gl is WebGL2RenderingContext { 32 | return ( 33 | self.WebGL2RenderingContext && gl instanceof self.WebGL2RenderingContext 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/core/shaders/canvas/HolePunch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import { calcFactoredRadiusArray } from '../../lib/utils.js'; 19 | import type { CanvasShaderType } from '../../renderers/canvas/CanvasShaderNode.js'; 20 | import type { Vec4 } from '../../renderers/webgl/internal/ShaderUtils.js'; 21 | import { 22 | HolePunchTemplate, 23 | type HolePunchProps, 24 | } from '../templates/HolePunchTemplate.js'; 25 | import { roundRect } from './utils/render.js'; 26 | 27 | export interface ComputedHolePunchValues { 28 | radius: Vec4; 29 | } 30 | 31 | export const HolePunch: CanvasShaderType< 32 | HolePunchProps, 33 | ComputedHolePunchValues 34 | > = { 35 | props: HolePunchTemplate.props, 36 | update() { 37 | this.computed.radius = calcFactoredRadiusArray( 38 | this.props!.radius as Vec4, 39 | this.props!.width, 40 | this.props!.height, 41 | ); 42 | }, 43 | render(ctx, quad, renderContext) { 44 | ctx.save(); 45 | renderContext(); 46 | const { x, y, width, height } = this.props!; 47 | ctx.beginPath(); 48 | roundRect( 49 | ctx, 50 | quad.tx + x, 51 | quad.ty + y, 52 | width, 53 | height, 54 | this.computed.radius!, 55 | ); 56 | ctx.closePath(); 57 | ctx.fillStyle = 'black'; 58 | ctx.globalCompositeOperation = 'destination-out'; 59 | ctx.fill(); 60 | ctx.restore(); 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /src/core/shaders/canvas/Rounded.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import { calcFactoredRadiusArray } from '../../lib/utils.js'; 19 | import type { CanvasShaderType } from '../../renderers/canvas/CanvasShaderNode.js'; 20 | import type { Vec4 } from '../../renderers/webgl/internal/ShaderUtils.js'; 21 | import { 22 | RoundedTemplate, 23 | type RoundedProps, 24 | } from '../templates/RoundedTemplate.js'; 25 | import { roundRect } from './utils/render.js'; 26 | 27 | export interface ComputedRoundedValues { 28 | radius: Vec4; 29 | } 30 | 31 | export const Rounded: CanvasShaderType = { 32 | props: RoundedTemplate.props, 33 | saveAndRestore: true, 34 | update(node) { 35 | this.computed.radius = calcFactoredRadiusArray( 36 | this.props!.radius as Vec4, 37 | node.width, 38 | node.height, 39 | ); 40 | }, 41 | render(ctx, quad, renderContext) { 42 | const path = new Path2D(); 43 | roundRect( 44 | path, 45 | quad.tx, 46 | quad.ty, 47 | quad.width, 48 | quad.height, 49 | this.computed.radius!, 50 | ); 51 | ctx.clip(path); 52 | 53 | renderContext(); 54 | }, 55 | }; 56 | -------------------------------------------------------------------------------- /src/core/shaders/canvas/Shadow.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { CanvasShaderType } from '../../renderers/canvas/CanvasShaderNode.js'; 19 | import type { Vec4 } from '../../renderers/webgl/internal/ShaderUtils.js'; 20 | import { 21 | ShadowTemplate, 22 | type ShadowProps, 23 | } from '../templates/ShadowTemplate.js'; 24 | import { shadow } from './utils/render.js'; 25 | 26 | export interface ComputedShadowValues { 27 | shadowColor: string; 28 | shadowRadius: Vec4; 29 | } 30 | 31 | export const Shadow: CanvasShaderType = { 32 | props: ShadowTemplate.props, 33 | update() { 34 | this.computed.shadowColor = this.toColorString(this.props!['color']); 35 | const blur = this.props!['blur']; 36 | this.computed.shadowRadius = [blur, blur, blur, blur]; 37 | }, 38 | render(ctx, quad, renderContext) { 39 | shadow( 40 | ctx, 41 | quad.tx, 42 | quad.ty, 43 | quad.width, 44 | quad.height, 45 | this.computed.shadowColor!, 46 | this.props!['projection'], 47 | this.computed.shadowRadius!, 48 | this.stage.pixelRatio, 49 | ); 50 | renderContext(); 51 | }, 52 | }; 53 | -------------------------------------------------------------------------------- /src/core/shaders/templates/LinearGradientTemplate.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { CoreShaderType } from '../../renderers/CoreShaderNode.js'; 19 | 20 | /** 21 | * Properties of the {@link LinearGradient} shader 22 | */ 23 | export interface LinearGradientProps { 24 | /** 25 | * Array of colors to be used in the LinearGradient shader 26 | * 27 | * @default [0xff000000, 0xffffffff] 28 | */ 29 | colors: number[]; 30 | /** 31 | * Angle of the LinearGradient shader, Angle in Radians 32 | * 33 | * @default 0 34 | */ 35 | angle: number; 36 | /** 37 | * Array of color stops 38 | */ 39 | stops: number[]; 40 | } 41 | 42 | export const LinearGradientTemplate: CoreShaderType = { 43 | props: { 44 | colors: { 45 | default: [0x000000ff, 0xffffffff], 46 | resolve(value) { 47 | if (value !== undefined && value.length > 0) { 48 | return value; 49 | } 50 | return ([] as number[]).concat(this.default); 51 | }, 52 | }, 53 | stops: { 54 | default: [0, 1], 55 | resolve(value, props) { 56 | if (value !== undefined && value.length === props.colors.length) { 57 | return value; 58 | } 59 | if (value === undefined) { 60 | value = []; 61 | } 62 | const len = props.colors.length; 63 | for (let i = 0; i < len; i++) { 64 | value[i] = i * (1 / (len - 1)); 65 | } 66 | return value; 67 | }, 68 | }, 69 | angle: 0, 70 | }, 71 | }; 72 | -------------------------------------------------------------------------------- /src/core/shaders/templates/RoundedWithBorderAndShadowTemplate.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { CoreShaderType } from '../../renderers/CoreShaderNode.js'; 19 | import { getBorderProps, type BorderProps } from './BorderTemplate.js'; 20 | import { RoundedTemplate, type RoundedProps } from './RoundedTemplate.js'; 21 | import type { PrefixedType } from '../utils.js'; 22 | import { getShadowProps, type ShadowProps } from './ShadowTemplate.js'; 23 | 24 | export type RoundedWithBorderAndShadowProps = RoundedProps & 25 | PrefixedType & 26 | PrefixedType; 27 | 28 | const props = Object.assign( 29 | {}, 30 | RoundedTemplate.props, 31 | getBorderProps('border'), 32 | getShadowProps('shadow'), 33 | ) as RoundedWithBorderAndShadowProps; 34 | 35 | export const RoundedWithBorderAndShadowTemplate: CoreShaderType = 36 | { 37 | props, 38 | }; 39 | -------------------------------------------------------------------------------- /src/core/shaders/templates/RoundedWithBorderTemplate.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { CoreShaderType } from '../../renderers/CoreShaderNode.js'; 19 | import { getBorderProps, type BorderProps } from './BorderTemplate.js'; 20 | import { RoundedTemplate, type RoundedProps } from './RoundedTemplate.js'; 21 | import type { PrefixedType } from '../utils.js'; 22 | 23 | export type RoundedWithBorderProps = RoundedProps & 24 | PrefixedType; 25 | 26 | const props = Object.assign( 27 | {}, 28 | RoundedTemplate.props, 29 | getBorderProps('border'), 30 | ) as RoundedWithBorderProps; 31 | 32 | export const RoundedWithBorderTemplate: CoreShaderType = 33 | { 34 | props, 35 | }; 36 | -------------------------------------------------------------------------------- /src/core/shaders/templates/RoundedWithShadowTemplate.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | 18 | import type { CoreShaderType } from '../../renderers/CoreShaderNode.js'; 19 | import { RoundedTemplate, type RoundedProps } from './RoundedTemplate.js'; 20 | import type { PrefixedType } from '../utils.js'; 21 | import { getShadowProps, type ShadowProps } from './ShadowTemplate.js'; 22 | 23 | export type RoundedWithShadowProps = RoundedProps & 24 | PrefixedType; 25 | 26 | const props = Object.assign( 27 | {}, 28 | RoundedTemplate.props, 29 | getShadowProps('shadow'), 30 | ) as RoundedWithShadowProps; 31 | 32 | export const RoundedWithShadowTemplate: CoreShaderType = 33 | { 34 | props, 35 | }; 36 | -------------------------------------------------------------------------------- /src/core/shaders/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Comcast Cable Communications Management, LLC 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | */ 17 | import { assertTruthy } from '../../utils.js'; 18 | import type { Vec4 } from '../renderers/webgl/internal/ShaderUtils.js'; 19 | 20 | export const validateArrayLength4 = (value: number | number[]): Vec4 => { 21 | if (!Array.isArray(value)) { 22 | return [value, value, value, value]; 23 | } 24 | assertTruthy(value); 25 | if (value.length === 4) { 26 | return value as Vec4; 27 | } 28 | if (value.length === 3) { 29 | value[3] = value[0]!; 30 | return value as Vec4; 31 | } 32 | if (value.length === 2) { 33 | value[2] = value[0]!; 34 | value[3] = value[1]!; 35 | return value as Vec4; 36 | } 37 | value[0] = value[0] || 0; 38 | value[1] = value[0]; 39 | value[2] = value[0]; 40 | value[3] = value[0]; 41 | return value as Vec4; 42 | }; 43 | 44 | export type PrefixedType = { 45 | [Key in keyof T as P extends string ? `${P}-${string & Key}` : Key]: T[Key]; 46 | }; 47 | -------------------------------------------------------------------------------- /src/core/text-rendering/TextRenderingUtils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2024 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | import type { NormalizedFontMetrics } from './font-face-types/TrFontFace.js'; 20 | 21 | /** 22 | * Calculate the default line height given normalized font metrics 23 | * 24 | * @remarks 25 | * This method may be used for both the WebTrFontFace and SdfTrFontFace font types. 26 | * 27 | * @param metrics 28 | * @param fontSize 29 | * @returns 30 | */ 31 | export function calcDefaultLineHeight( 32 | metrics: NormalizedFontMetrics, 33 | fontSize: number, 34 | ): number { 35 | return fontSize * (metrics.ascender - metrics.descender + metrics.lineGap); 36 | } 37 | -------------------------------------------------------------------------------- /src/core/text-rendering/font-face-types/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2020 Metrological 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | export function fetchJson( 20 | url: string, 21 | responseType: XMLHttpRequestResponseType = '', 22 | ): Promise { 23 | return new Promise((resolve, reject) => { 24 | const xhr = new XMLHttpRequest(); 25 | xhr.responseType = responseType; 26 | xhr.onreadystatechange = function () { 27 | if (xhr.readyState == XMLHttpRequest.DONE) { 28 | // On most devices like WebOS and Tizen, the file protocol returns 0 while http(s) protocol returns 200 29 | if (xhr.status === 0 || xhr.status === 200) { 30 | resolve(xhr.response); 31 | } else { 32 | reject(xhr.statusText); 33 | } 34 | } 35 | }; 36 | xhr.open('GET', url, true); 37 | xhr.send(null); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import { describe, expect, it } from 'vitest'; 21 | import { PeekableIterator } from './PeekableGenerator.js'; 22 | 23 | describe('PeekableIterator', () => { 24 | it('should be able to peek at the next value.', () => { 25 | const iterator = new PeekableIterator([1, 2, 3].values()); 26 | expect(iterator.peek()).toEqual({ done: false, value: 1 }); 27 | expect(iterator.next()).toEqual({ done: false, value: 1 }); 28 | expect(iterator.peek()).toEqual({ done: false, value: 2 }); 29 | expect(iterator.next()).toEqual({ done: false, value: 2 }); 30 | expect(iterator.peek()).toEqual({ done: false, value: 3 }); 31 | expect(iterator.next()).toEqual({ done: false, value: 3 }); 32 | expect(iterator.peek()).toEqual({ done: true, value: undefined }); 33 | expect(iterator.next()).toEqual({ done: true, value: undefined }); 34 | }); 35 | 36 | it('should be able to return the last index of the iterator.', () => { 37 | const iterator = new PeekableIterator([1, 2, 3].values()); 38 | expect(iterator.lastIndex).toBe(-1); 39 | iterator.next(); 40 | expect(iterator.lastIndex).toBe(0); 41 | iterator.next(); 42 | expect(iterator.lastIndex).toBe(1); 43 | iterator.next(); 44 | expect(iterator.lastIndex).toBe(2); 45 | iterator.next(); 46 | expect(iterator.lastIndex).toBe(-1); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * A wrapper Generator class that makes a generator peekable. 22 | */ 23 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 | export class PeekableIterator 25 | implements Iterator 26 | { 27 | private peekBuffer: IteratorResult[] = []; 28 | private _lastIndex; 29 | 30 | constructor(private iterator: Iterator, indexBase = 0) { 31 | this.iterator = iterator; 32 | this._lastIndex = indexBase - 1; 33 | this.peekBuffer = []; 34 | } 35 | 36 | next(): IteratorResult { 37 | const nextResult = 38 | this.peekBuffer.length > 0 39 | ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 40 | this.peekBuffer.pop()! 41 | : this.iterator.next(); 42 | 43 | if (nextResult.done) { 44 | this._lastIndex = -1; 45 | } else { 46 | this._lastIndex++; 47 | } 48 | return nextResult; 49 | } 50 | 51 | peek(): IteratorResult { 52 | if (this.peekBuffer.length > 0) { 53 | // We know that the buffer is not empty, so we can safely use the 54 | // non-null assertion operator 55 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 56 | return this.peekBuffer[0]!; 57 | } 58 | const result = this.iterator.next(); 59 | this.peekBuffer.push(result); 60 | return result; 61 | } 62 | 63 | get lastIndex(): number { 64 | return this._lastIndex; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | export const SpecialCodepoints = { 21 | LINE_FEED: 0x0a, 22 | CARRIAGE_RETURN: 0x0d, 23 | SPACE: 0x20, 24 | TAB: 0x09, 25 | ZERO_WIDTH_SPACE: 0x200b, 26 | ZERO_WIDTH_NON_JOINER: 0x200c, 27 | ZERO_WIDTH_JOINER: 0x200d, 28 | LEFT_TO_RIGHT_MARK: 0x200e, 29 | RIGHT_TO_LEFT_MARK: 0x200f, 30 | LEFT_TO_RIGHT_EMBEDDING: 0x202a, 31 | RIGHT_TO_LEFT_EMBEDDING: 0x202b, 32 | POP_DIRECTIONAL_FORMATTING: 0x202c, 33 | LEFT_TO_RIGHT_OVERRIDE: 0x202d, 34 | RIGHT_TO_LEFT_OVERRIDE: 0x202e, 35 | LINE_SEPARATOR: 0x2028, 36 | PARAGRAPH_SEPARATOR: 0x2029, 37 | OBJECT_REPLACEMENT_CHARACTER: 0xfffc, 38 | REPLACEMENT_CHARACTER: 0xfffd, 39 | ZERO_WIDTH_NO_BREAK_SPACE: 0xfeff, 40 | LEFT_TO_RIGHT_ISOLATE: 0x2066, 41 | RIGHT_TO_LEFT_ISOLATE: 0x2067, 42 | FIRST_STRONG_ISOLATE: 0x2068, 43 | POP_DIRECTIONAL_ISOLATE: 0x2069, 44 | INHIBIT_SYMMETRIC_SWAPPING: 0x206a, 45 | ACTIVATE_SYMMETRIC_SWAPPING: 0x206b, 46 | INHIBIT_ARABIC_FORM_SHAPING: 0x206c, 47 | ACTIVATE_ARABIC_FORM_SHAPING: 0x206d, 48 | NATIONAL_DIGIT_SHAPES: 0x206e, 49 | NOMINAL_DIGIT_SHAPES: 0x206f, 50 | LEFT_TO_RIGHT_BOUNDARY: 0x200e, 51 | RIGHT_TO_LEFT_BOUNDARY: 0x200f, 52 | }; 53 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * Number of floating point numbers that represent a single glyph in the SDF vertex buffer. 22 | * 23 | * @remarks 24 | * The vertex buffer contains: 25 | * - 6 vertex positions 26 | * - 6 texture coordinates 27 | * - = 12 positions/coordinates per glyph 28 | * 29 | * Each vertex position and texture coordinate consist of 2 floating point numbers (x/y). 30 | * So there are 12 * 2 = 24 floating point numbers that make up a single glyph. 31 | */ 32 | export const FLOATS_PER_GLYPH = 24; 33 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | // Reversible Generator Wrapper Class 21 | 22 | /** 23 | * Generator function that yields each Unicode code point in the given string. 24 | */ 25 | export function* getUnicodeCodepoints( 26 | text: string, 27 | start = 0, 28 | ): Generator { 29 | let i = start; 30 | while (i < text.length) { 31 | const codePoint = text.codePointAt(i); 32 | if (codePoint === undefined) { 33 | throw new Error('Invalid Unicode code point'); 34 | } 35 | yield codePoint; 36 | i += codePoint <= 0xffff ? 1 : 2; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import { expect, describe, it } from 'vitest'; 21 | import { measureText } from './measureText.js'; 22 | import sdfData from 'test/mockdata/Ubuntu-Bold.msdf.json'; 23 | import { 24 | SdfFontShaper, 25 | type SdfFontData, 26 | } from '../../../font-face-types/SdfTrFontFace/internal/SdfFontShaper.js'; 27 | 28 | const glyphMap = new Map(); 29 | sdfData.chars.forEach((glyph) => { 30 | glyphMap.set(glyph.id, glyph); 31 | }); 32 | 33 | describe('measureText', () => { 34 | it('should measure text width', () => { 35 | const PERIOD_WIDTH = 10.332; 36 | const shaper = new SdfFontShaper( 37 | sdfData as unknown as SdfFontData, 38 | glyphMap, 39 | ); 40 | expect(measureText('', { letterSpacing: 0 }, shaper)).toBe(0); 41 | expect(measureText('.', { letterSpacing: 0 }, shaper)).toBe(PERIOD_WIDTH); 42 | expect(measureText('..', { letterSpacing: 0 }, shaper)).toBeCloseTo( 43 | PERIOD_WIDTH * 2, 44 | ); 45 | expect(measureText('..', { letterSpacing: 5 }, shaper)).toBeCloseTo( 46 | PERIOD_WIDTH * 2 + 5, 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { 21 | FontShaper, 22 | FontShaperProps, 23 | } from '../../../font-face-types/SdfTrFontFace/internal/FontShaper.js'; 24 | import { PeekableIterator } from './PeekableGenerator.js'; 25 | import { getUnicodeCodepoints } from './getUnicodeCodepoints.js'; 26 | 27 | /** 28 | * Measures a single-line of text width ignoring any unmapped glyphs including line breaks 29 | * 30 | * @param text 31 | * @param shaperProps 32 | * @param shaper 33 | * @returns 34 | */ 35 | export function measureText( 36 | text: string, 37 | shaperProps: FontShaperProps, 38 | shaper: FontShaper, 39 | ): number { 40 | const glyphs = shaper.shapeText( 41 | shaperProps, 42 | new PeekableIterator(getUnicodeCodepoints(text, 0), 0), 43 | ); 44 | let width = 0; 45 | for (const glyph of glyphs) { 46 | if (glyph.mapped && glyph.codepoint !== 8203) { 47 | // Skip ZWSP (\u200B) 48 | width += glyph.xAdvance; 49 | } 50 | } 51 | return width; 52 | } 53 | -------------------------------------------------------------------------------- /src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * Round up to the nearest multiple of the given number. 22 | * 23 | * @param value 24 | * @param multiple 25 | * @returns 26 | */ 27 | export function roundUpToMultiple(value: number, multiple: number) { 28 | return Math.ceil(value / multiple) * multiple; 29 | } 30 | 31 | /** 32 | * Round down to the nearest multiple of the given number. 33 | * 34 | * @param value 35 | * @param multiple 36 | * @returns 37 | */ 38 | export function roundDownToMultiple(value: number, multiple: number) { 39 | return Math.floor(value / multiple) * multiple; 40 | } 41 | -------------------------------------------------------------------------------- /src/core/textures/RenderTexture.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * If not stated otherwise in this file or this component's LICENSE file the 3 | * following copyright and licenses apply: 4 | * 5 | * Copyright 2023 Comcast Cable Communications Management, LLC. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the License); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import type { CoreTextureManager } from '../CoreTextureManager.js'; 21 | import { Texture, TextureType, type TextureData } from './Texture.js'; 22 | 23 | /** 24 | * Properties of the {@link RenderTexture} 25 | */ 26 | export interface RenderTextureProps { 27 | /** 28 | * WebGL Texture width 29 | * @default 256 30 | */ 31 | width?: number; 32 | 33 | /** 34 | * WebGL Texture height 35 | * @default 256 36 | */ 37 | height?: number; 38 | } 39 | 40 | export class RenderTexture extends Texture { 41 | props: Required; 42 | 43 | public override type: TextureType = TextureType.renderToTexture; 44 | 45 | constructor(txManager: CoreTextureManager, props?: RenderTextureProps) { 46 | super(txManager); 47 | this.props = RenderTexture.resolveDefaults(props || {}); 48 | } 49 | 50 | get width() { 51 | return this.props.width; 52 | } 53 | 54 | set width(value: number) { 55 | this.props.width = value; 56 | } 57 | 58 | get height() { 59 | return this.props.height; 60 | } 61 | 62 | set height(value: number) { 63 | this.props.height = value; 64 | } 65 | 66 | override async getTextureSource(): Promise { 67 | this.setState('fetched'); 68 | 69 | return { 70 | data: null, 71 | premultiplyAlpha: null, 72 | }; 73 | } 74 | 75 | static override resolveDefaults( 76 | props: RenderTextureProps, 77 | ): Required { 78 | return { 79 | width: props.width || 256, 80 | height: props.height || 256, 81 | }; 82 | } 83 | 84 | static z$__type__Props: RenderTextureProps; 85 | } 86 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | interface ImportMetaEnv { 2 | readonly PROD: boolean; 3 | } 4 | 5 | interface ImportMeta { 6 | readonly env: ImportMetaEnv; 7 | } 8 | -------------------------------------------------------------------------------- /src/main-api/utils.ts: -------------------------------------------------------------------------------- 1 | import type { CustomDataMap } from '../core/CoreNode.js'; 2 | 3 | export function santizeCustomDataMap(d: CustomDataMap): CustomDataMap { 4 | const validTypes = { 5 | boolean: true, 6 | string: true, 7 | number: true, 8 | undefined: true, 9 | }; 10 | 11 | const keys = Object.keys(d); 12 | for (let i = 0; i < keys.length; i++) { 13 | const key = keys[i]; 14 | if (!key) { 15 | continue; 16 | } 17 | 18 | const value = d[key]; 19 | const valueType = typeof value; 20 | 21 | // Typescript doesn't understand the above const valueType ¯\_(ツ)_/¯ 22 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 23 | // @ts-ignore-next-line 24 | if (valueType === 'string' && value.length > 2048) { 25 | console.warn( 26 | `Custom Data value for ${key} is too long, it will be truncated to 2048 characters`, 27 | ); 28 | 29 | // same here, see above comment, this can only be a string at this point 30 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 31 | // @ts-ignore-next-line 32 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call 33 | d[key] = value.substring(0, 2048); 34 | } 35 | 36 | if (!validTypes[valueType as keyof typeof validTypes]) { 37 | console.warn( 38 | `Custom Data value for ${key} is not a boolean, string, or number, it will be ignored`, 39 | ); 40 | delete d[key]; 41 | } 42 | } 43 | 44 | return d; 45 | } 46 | -------------------------------------------------------------------------------- /tsconfig.cfg.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist-cfg", 4 | "types": ["@types/node"], 5 | "target": "ESNext", 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "composite": true, 9 | "resolveJsonModule": true, 10 | "allowJs": true, 11 | "esModuleInterop": true, 12 | }, 13 | "files": [ 14 | "./examples/vite.config.ts", 15 | "./typedoc.config.cjs" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | }, 6 | "include": ["./src/**/*.ts", "./exports/**/*.ts"], 7 | "exclude": ["node_modules", "./**/*.test.ts"], 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "types": [], 5 | "lib": ["ES2022", "DOM"], 6 | "outDir": "dist", 7 | "allowJs": true, 8 | "target": "ES2022", 9 | "module": "Node16", 10 | "moduleResolution": "Node16", 11 | "sourceMap": true, 12 | "declaration": true, 13 | "experimentalDecorators": true, 14 | 15 | // Type Checking / Syntax Rules 16 | "strict": true, 17 | "noUncheckedIndexedAccess": true, 18 | "noImplicitOverride": true, 19 | "noImplicitAny": false, 20 | "allowSyntheticDefaultImports": true, 21 | "resolveJsonModule": true, 22 | "verbatimModuleSyntax": true, 23 | "composite": true, 24 | }, 25 | "files": [], 26 | "references": [ 27 | { 28 | "path": "./tsconfig.cfg.json" 29 | }, 30 | { 31 | "path": "./tsconfig.vitest.json" 32 | }, 33 | { 34 | "path": "./tsconfig.dist.json" 35 | } 36 | ], 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.vitest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist-vitest", 5 | "types": [], 6 | "composite": true, 7 | "module": "esnext", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "paths": { 11 | "test/*": ["./test/*"] 12 | }, 13 | }, 14 | "include": [ 15 | "./src/**/*.ts", 16 | "./exports/**/*.ts", 17 | "./test/mockdata/**/*.json" 18 | ], 19 | "exclude": [ 20 | "./src/core/renderers/webgl/effect/*.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /typedoc.config.cjs: -------------------------------------------------------------------------------- 1 | /* global module */ 2 | /** @type {import('typedoc').TypeDocOptions} */ 3 | module.exports = { 4 | entryPoints: [ 5 | './exports/index.ts', 6 | './exports/webgl.ts', 7 | './exports/webgl-shaders.ts', 8 | './exports/canvas.ts', 9 | './exports/canvas-shaders.ts', 10 | './exports/utils.ts', 11 | ], 12 | out: 'typedocs', 13 | }; 14 | -------------------------------------------------------------------------------- /visual-regression/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict = true 2 | -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/alignment-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/alignment-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/alpha-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/alpha-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/alpha-blending-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/alpha-blending-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/alpha-blending-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/alpha-blending-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a1-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a1-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a1-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a1-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a2-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a2-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a2-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a2-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a3-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/animation-events_a3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/animation-events_a3-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clear-color-setting-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clear-color-setting-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clear-color-setting-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clear-color-setting-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clear-color-setting-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clear-color-setting-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clipping-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clipping-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clipping-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clipping-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clipping-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clipping-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clipping-mutations-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clipping-mutations-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clipping-mutations-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clipping-mutations-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/clipping-mutations-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/clipping-mutations-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/destroy-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/destroy-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/destroy-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/destroy-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/ds-effect-radial-progress-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/ds-effect-radial-progress-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/dynamic-shader-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/dynamic-shader-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/dynamic-shader-circle-border-radius-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/dynamic-shader-circle-border-radius-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/hole-punch-effect-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/hole-punch-effect-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/quads-rendered-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/quads-rendered-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/quads-rendered-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/quads-rendered-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/render-settings-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/render-settings-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/render-settings-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/render-settings-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/render-settings-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/render-settings-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/render-settings-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/render-settings-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/render-settings-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/render-settings-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/render-settings-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/render-settings-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/resize-mode-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/resize-mode-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/resize-mode-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/resize-mode-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/resize-mode-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/resize-mode-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/resize-mode-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/resize-mode-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-dimension-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-dimension-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-dimension-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-dimension-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-dimension-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-dimension-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-dimension-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-dimension-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-dimension-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-dimension-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-dimension-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-dimension-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/rtt-spritemap-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/rtt-spritemap-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/scaling-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/scaling-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/scaling-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/scaling-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/scaling-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/scaling-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-animation_animation1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-animation_animation1-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-animation_animation2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-animation_animation2-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-animation_startup-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-animation_startup-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-border-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-border-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-hole-punch-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-hole-punch-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-linear-gradient-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-linear-gradient-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-radial-gradient-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-radial-gradient-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-rounded-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-rounded-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/shader-shadow-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/shader-shadow-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-align-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-align-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-align-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-align-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-align-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-align-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-align-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-align-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-align-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-align-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-align-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-align-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-alpha-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-alpha-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-alpha-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-alpha-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-baseline-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-baseline-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-canvas-font-no-metrics-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-canvas-font-no-metrics-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-canvas-font-no-metrics-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-canvas-font-no-metrics-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-10.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-7.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-8.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-contain-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-contain-9.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-dimensions-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-dimensions-7.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-modified-metrics-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-modified-metrics-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-modified-metrics-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-modified-metrics-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-modified-metrics-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-layout-consistency-modified-metrics-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-line-height-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-line-height-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-max-lines-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-max-lines-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-max-lines-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-max-lines-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-mixed-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-mixed-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-offscreen-move-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-overflow-suffix-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-overflow-suffix-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-rotation-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-rotation-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-rotation-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-rotation-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-scaling-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-scaling-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-scaling-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-scaling-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-scaling-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-scaling-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-scaling-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-scaling-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-scaling-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-scaling-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-scaling-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-scaling-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-ssdf-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-ssdf-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-vertical-align-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-vertical-align-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-vertical-align-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-wordbreak-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-wordbreak-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-wordbreak-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-wordbreak-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-wordbreak-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-wordbreak-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-wordbreak-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-wordbreak-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-zwsp-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-zwsp-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-zwsp-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-zwsp-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/text-zwsp-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/text-zwsp-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/texture-autosize-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/texture-autosize-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/texture-base64-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/texture-base64-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/texture-factory-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/texture-factory-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/texture-source-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/texture-source-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/texture-spritemap-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/texture-spritemap-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/texture-svg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/texture-svg-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/textures-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/textures-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-10.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-11.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-12.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-7.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-8.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-boundsmargin-9.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-10.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-11.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-12.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-13.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-14.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-15.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-16.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-17.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-18.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-4.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-5.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-6.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-7.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-8.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-events-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-events-9.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-largebound-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-largebound-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-largebound-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-largebound-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-largebound-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-largebound-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-strictbounds-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-strictbounds-1.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-strictbounds-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-strictbounds-2.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/viewport-strictbounds-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/viewport-strictbounds-3.png -------------------------------------------------------------------------------- /visual-regression/certified-snapshots/chromium-ci/zIndex-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightning-js/renderer/d4867e5855e38a75f4875c8172fba883afa0a761/visual-regression/certified-snapshots/chromium-ci/zIndex-1.png -------------------------------------------------------------------------------- /visual-regression/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "visual-regression", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "private": true, 8 | "scripts": { 9 | "start": "pnpm test:visual", 10 | "test:visual": "tsc && node dist/src/index.js", 11 | "build": "tsc", 12 | "build:renderer": "cd .. && pnpm build", 13 | "build:examples": "cd ../examples && pnpm build", 14 | "build:docker": "tsc && node dist/src/build-docker.js", 15 | "serve-examples": "cd ../examples && pnpm preview:automation", 16 | "node-version": "node --version" 17 | }, 18 | "keywords": [], 19 | "author": "", 20 | "license": "Apache-2.0", 21 | "devDependencies": { 22 | "@types/fs-extra": "^11.0.4", 23 | "@types/node": "^18.18.6", 24 | "@types/pixelmatch": "^5.2.6", 25 | "@types/pngjs": "^6.0.5", 26 | "@types/yargs": "^17.0.31", 27 | "playwright": "^1.39.0", 28 | "wait-port": "^1.1.0" 29 | }, 30 | "dependencies": { 31 | "chalk": "^5.3.0", 32 | "execa": "^8.0.1", 33 | "fs-extra": "^11.1.1", 34 | "yargs": "^17.7.2", 35 | "pngjs": "^7.0.0", 36 | "pixelmatch": "^6.0.0" 37 | }, 38 | "engines": { 39 | "npm": "please-use-pnpm" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /visual-regression/src/build-docker.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ts-node 2 | 3 | import { $ } from 'execa'; 4 | import { argv } from 'process'; 5 | import path from 'path'; 6 | import { fileURLToPath } from 'url'; 7 | 8 | import { detectContainerRuntime } from './detectDockerRuntime.js'; 9 | 10 | /** 11 | * Builds a container image using the detected container runtime. 12 | * Changes the working directory to one level higher than the script's location. 13 | * @param runtime - The container runtime (`podman` or `docker`). 14 | * @param imageName - The name of the container image to build. 15 | */ 16 | async function buildContainer( 17 | runtime: string, 18 | imageName: string, 19 | ): Promise { 20 | // Change working directory to one level higher than the script's location 21 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 22 | const scriptDir = path.resolve(__dirname, '../../../'); 23 | process.chdir(scriptDir); 24 | 25 | console.log(`Working directory changed to: ${scriptDir}`); 26 | console.log(`Using ${runtime} to build the container image: ${imageName}`); 27 | try { 28 | await $({ stdio: 'inherit' })`${runtime} build -t ${imageName} .`; 29 | } catch (error) { 30 | console.error(`Failed to build the image with ${runtime}.`, error); 31 | process.exit(1); 32 | } 33 | } 34 | 35 | (async () => { 36 | const imageName = argv[2] || 'visual-regression'; // Default image name 37 | try { 38 | const runtime = await detectContainerRuntime(); 39 | await buildContainer(runtime, imageName); 40 | } catch (error) { 41 | if (error instanceof Error) { 42 | console.error(error.message); 43 | } else { 44 | console.error(error); 45 | } 46 | process.exit(1); 47 | } 48 | })(); 49 | -------------------------------------------------------------------------------- /visual-regression/src/detectDockerRuntime.ts: -------------------------------------------------------------------------------- 1 | import { $ } from 'execa'; 2 | 3 | /** 4 | * Detects the available container runtime (podman or docker). 5 | * @returns {Promise} The name of the container runtime (`podman` or `docker`). 6 | * @throws {Error} If neither runtime is found. 7 | */ 8 | export async function detectContainerRuntime(): Promise<'docker' | 'podman'> { 9 | try { 10 | await $`podman -v`; 11 | return 'podman'; 12 | } catch { 13 | try { 14 | await $`docker -v`; 15 | return 'docker'; 16 | } catch { 17 | throw new Error( 18 | 'Neither podman nor docker is installed. Please install one of them.', 19 | ); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /visual-regression/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "dist", 6 | "types": ["node"], 7 | "lib": ["ES2022", "DOM"], 8 | }, 9 | "include": [ 10 | "src/**/*", 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | provider: 'v8', 7 | all: true, 8 | include: ['src/**/*.ts'], 9 | }, 10 | }, 11 | }); 12 | --------------------------------------------------------------------------------