Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI

on:
push

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22.x"
registry-url: "https://registry.npmjs.org"

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Install dependencies
run: |
pnpm install

- name: Check code formatting
run: |
pnpm run format:check
Comment on lines +30 to +31
Copy link

Copilot AI Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove trailing whitespace after the pipe character on line 30 and after 'format:check' on line 31. Trailing whitespace in YAML files can cause inconsistencies and should be avoided.

Suggested change
run: |
pnpm run format:check
run: |
pnpm run format:check

Copilot uses AI. Check for mistakes.
21 changes: 21 additions & 0 deletions .github/workflows/semantic-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: "Semantic PR"

on:
pull_request_target:
types:
- opened
- reopened
- edited
- synchronize

permissions:
pull-requests: read

jobs:
validate-pr-title:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44 changes: 23 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# React SVG Shape


<img src="https://github.com/user-attachments/assets/3a473b65-cdd9-4a00-abbd-66fcd9b52644" width="200px" style="margin: auto;"/>


# Installation

[NPM](https://www.npmjs.com/package/react-svg-shape)

```bash
npm i react-svg-shape
```
Expand All @@ -16,17 +16,18 @@ npm i react-svg-shape
import { generatePath, SvgShape } from "react-svg-shape";

const svgPath = generatePath({ complexity: 16, contrast: 4 });

const SvgBlobComponent = () => {
return (
<SvgShape width={100} height={100}>
<SvgShape.Path svgPath={svgPath} colors={["#f87537", "#fba81f"]} />
</SvgShape>
);
}
return (
<SvgShape width={100} height={100}>
<SvgShape.Path svgPath={svgPath} colors={["#f87537", "#fba81f"]} />
</SvgShape>
);
};
```

## Animated Blob

> [!IMPORTANT]
> SVG animations are supported only in Chromium based browsers

Expand All @@ -37,7 +38,7 @@ import { generatePath, SvgShape } from "react-svg-shape";
const INTERVAL_DURATION = 1_000;
const generateShapePath = () => generatePath({ complexity: 16, contrast: 4 });

const SvgBlobAnimatedComponent = () => {
const SvgBlobAnimatedComponent = () => {
const [svgPath, setSvgPath] = useState(generateShapePath());

useEffect(() => {
Expand All @@ -51,20 +52,21 @@ const SvgBlobAnimatedComponent = () => {
}, [setSvgPath]);

return (
<SvgShape width={100} height={100}>
<SvgShape.Path
svgPath={svgPath}
colors={["#f87537", "#fba81f"]}
style={{
transition: `all ${INTERVAL_DURATION / 1000}s linear`,
}}
/>
</SvgShape>
<SvgShape width={100} height={100}>
<SvgShape.Path
svgPath={svgPath}
colors={["#f87537", "#fba81f"]}
style={{
transition: `all ${INTERVAL_DURATION / 1000}s linear`,
}}
/>
</SvgShape>
);
}
};
```

<img src="https://github.com/user-attachments/assets/bf581601-d02e-4b5c-9eb9-8badac486634" alt="Animated Blob" width="100%"/>

## Honorable Mention
https://www.softr.io/tools/svg-shape-generator

https://www.softr.io/tools/svg-shape-generator
2 changes: 1 addition & 1 deletion apps/docs/src/components/AnimatedBlob.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const AnimatedBlob = ({ className }: { className?: string }) => {
generatePath({ complexity: 16, contrast: 4 }),
generatePath({ complexity: 16, contrast: 6 }),
],
[]
[],
);

const [shapes, setShapes] = useState<string[]>(handleGenerateShapes);
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/lib/utils/downloadSVG.utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function downloadSVG(
svgContent: string,
filename: string = "generated-shape.svg"
filename: string = "generated-shape.svg",
): void {
const blob = new Blob([svgContent], { type: "image/svg+xml" });
const url = window.URL.createObjectURL(blob);
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import "./index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>
</StrictMode>,
);
2 changes: 1 addition & 1 deletion apps/docs/src/sections/SvgGeneratorSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const SvgGeneratorSection: FC<SvgGeneratorProps> = () => {
contrast: curve,
});
},
[]
[],
);

const generateRandomShape = useCallback(() => {
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
"scripts": {
"build": "turbo run build",
"preview": "turbo run preview",
"dev": "turbo run dev"
"dev": "turbo run dev",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"format:check": "prettier --check \"**/*.{ts,tsx,md}\""
},
"devDependencies": {
"prettier": "^3.6.2",
"turbo": "^2.5.8"
},
"packageManager": "[email protected]"
Expand Down
6 changes: 3 additions & 3 deletions packages/react-svg-shape/src/shape-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function roundPath(path: string, precision: number = 0.1): string {
if (!path) return "";
const query = /[\d.-][\d.e-]*/g;
return path.replace(query, (n: string) =>
String(Math.round(Number(n) * (1 / precision)) / (1 / precision))
String(Math.round(Number(n) * (1 / precision)) / (1 / precision)),
);
}

Expand Down Expand Up @@ -49,7 +49,7 @@ export function createSVGContent(
path: string,
color1: string,
color2?: string,
stroke: boolean = false
stroke: boolean = false,
): string {
const fillColor = stroke ? "none" : color2 ? "url(#gradient)" : color1;

Expand Down Expand Up @@ -79,7 +79,7 @@ export function createSimpleSVGContent(
path: string,
color1: string,
color2?: string,
stroke: boolean = false
stroke: boolean = false,
): string {
const fillColor = stroke ? "none" : color2 ? "url(#gradient)" : color1;

Expand Down
35 changes: 27 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.