-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
feat(svg): add native p5.svg experimental feature module and contributor docs #9123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
VANSH3104
wants to merge
7
commits into
processing:main
Choose a base branch
from
VANSH3104:feat/svg-integration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2323cc4
docs(experimental): add p5.svg experimental warning message and contr…
VANSH3104 e9bf36e
feat(svg): add ShapeRecorder AST node hierarchy and transform stack i…
VANSH3104 dfa6255
feat(svg): add SVGExportAddon and SVGVisitor renderer implementation
VANSH3104 e8e0eac
feat(svg): add SVGImportAddon, path command tokenizer, and element co…
VANSH3104 ff8c36d
feat(svg): add p5.svg entry point with experimental decorators and re…
VANSH3104 8b7e241
docs(svg): update contributor documentation based on review feedback
VANSH3104 87854f6
Merge branch 'main' into feat/svg-integration
VANSH3104 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| <!-- An overview of the goals of p5's native SVG export, import, and vector shape recording system. --> | ||
|
|
||
| # p5.svg Overview | ||
|
|
||
| `p5.svg` is an experimental native vector graphics system provided in p5.js starting from version 2.4. It allows you to create, import, and export vector graphics directly in p5.js without needing external addons. With `p5.svg`, artists, designers, and educators can generate graphics that scale smoothly for high-DPI displays, print, pen plotters, CNC routers, laser cutters, and embroidery machines using familiar p5.js drawing functions. | ||
|
|
||
| The specifics of these APIs are currently experimental and subject to evolution based on community feedback. A valuable contribution to the project is testing these APIs, reporting edge cases, and sharing feedback on usability and performance! | ||
|
|
||
| ## Project Goals | ||
|
|
||
| `p5.svg` addresses several key goals: | ||
|
|
||
| - **Vector Graphics**: `p5.svg` allows p5.js drawings to be saved as vector graphics that can scale to different sizes without losing sharpness. | ||
| - **Familiar p5 Drawing Workflow**: To create SVG output, the only thing you need to do differently is use `createShape()` and `buildShape()`. Inside these functions, use the standard drawing API (`rect`, `circle`, `path`, `fill`, `stroke`, `translate`, `rotate`, etc.) as you usually would. | ||
| - **Import and Export SVG Files**: `p5.svg` allows you to load existing SVG files with `loadSVG()` and save p5.js drawings as SVG files using `saveSVG()` or `getSVG()`. | ||
|
|
||
| ## What Needs Feedback | ||
|
|
||
| The main ways you can help develop `p5.svg` are: | ||
|
|
||
| - **Shape API**: Test vector shape functions like `createSVG()`, `loadSVG()`, `buildShape()`, `createShape()`, `shape()`, `getSVG()`, and `saveSVG()`. We want feedback on whether the API feels familiar to someone learning p5.js, whether the functions are easy to understand for beginners, and whether they are easy to use when teaching p5.js. Let us know if any choices feel confusing or tricky for students, or if anything feels inconsistent with the rest of p5.js. | ||
| - **SVG Path Parsing**: Test importing SVGs generated by vector design tools (Adobe Illustrator, Inkscape, Figma). Report any unsupported path commands (`M`, `L`, `H`, `V`, `C`, `S`, `Q`, `T`, `A`, `Z`) or malformed elements. | ||
| - **Styling and CSS Properties**: Help verify that stroke weights, colors, fill rules, opacities, gradients, and transform stacks behave consistently across export and import pipelines. | ||
| - **Performance & Memory**: Test large or complex SVG scenes to help identify bottlenecks in DOM parsing, AST construction, or XML string generation. | ||
|
|
||
| ## Technical Overview | ||
|
|
||
| Behind the scenes, `p5.svg` operates in three main layers: | ||
|
|
||
| 1. **Shape Recording (`src/shape/svg/svg_recorder.js`)**: | ||
| - Intercepts 2D drawing calls (`rect`, `ellipse`, `line`, `beginShape`/`endShape`, `fill`, `stroke`, `push`, `pop`, `translate`, `rotate`, `scale`, `applyMatrix`). | ||
| - Builds an Abstract Syntax Tree (AST) composed of node instances (`ScopeNode`, `ShapeNode`, `BackgroundNode`, `ClearNode`, `ImageNode`). | ||
| - Tracks coordinate transformations using an internal `TransformStack`. | ||
|
|
||
| 2. **SVG Export & Visitor (`src/shape/svg/svg_export.js`)**: | ||
| - Implements `SVGExportAddon` and `SVGVisitor` (extending `p5.PrimitiveVisitor`). | ||
| - Traverses the shape AST to output standard SVG 2.0 XML markup string via `getSVG()` or triggers browser file downloads via `saveSVG()`. | ||
|
|
||
| 3. **SVG Import & Parsing (`src/shape/svg/svg_import.js`)**: | ||
| - Implements `SVGImportAddon` to parse external SVG DOM trees. | ||
| - Tokenizes path data commands (`PATH_COMMANDS`) and converts SVG elements (`<path>`, `<rect>`, `<circle>`, `<ellipse>`, `<line>`, `<polyline>`, `<polygon>`, `<g>`) into internal p5 `RecordedShape` structures ready for playback via `shape()`. | ||
|
|
||
| ## Usage Example | ||
|
|
||
| ### Exporting an SVG | ||
|
|
||
| ```js | ||
| function setup() { | ||
| createCanvas(400, 400); | ||
|
|
||
| // Record drawing commands into a vector shape | ||
| const record = buildShape(() => { | ||
| background(245); | ||
| fill(99, 102, 241); | ||
| stroke(0); | ||
| strokeWeight(2); | ||
| circle(200, 200, 150); | ||
| }); | ||
|
|
||
| // Save as vector file | ||
| saveSVG(record, 'my-vector.svg'); | ||
| } | ||
| ``` | ||
|
|
||
| ### Importing and Replaying an SVG | ||
|
|
||
| ```js | ||
| let botLogo; | ||
|
|
||
| async function setup() { | ||
| createCanvas(500, 500); | ||
|
|
||
| try { | ||
| // loadSVG returns a promise; await the resolved RecordedShape | ||
| botLogo = await loadSVG('assets/robot.svg'); | ||
| console.log('SVG Loaded successfully!'); | ||
| } catch (err) { | ||
| console.error('Failed to load SVG:', err); | ||
| } | ||
| } | ||
|
|
||
| function draw() { | ||
| background(255); | ||
|
|
||
| // Render the SVG once it is fully loaded | ||
| if (botLogo) { | ||
| shape(botLogo, 100, 100); | ||
| } else { | ||
| fill(100); | ||
| text('Loading SVG...', 20, 30); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Contributing | ||
|
|
||
| We welcome contributions to `p5.svg`! You can get involved by: | ||
|
|
||
| * **Testing existing SVG workflows** and reporting bugs or unexpected behavior on GitHub. | ||
| * **Proposing and implementing new SVG features**, such as expanded SVG element support, clipping paths, gradients, filters, and custom SVG attributes. | ||
| * **Improving SVG import and parsing**, including support for additional path commands and CSS/SVG attributes. | ||
| * **Adding tests and examples** to validate new functionality and demonstrate real-world SVG workflows. | ||
| * **Creating tutorials and creative coding examples** that showcase how `p5.svg` can be used in p5.js projects. | ||
| * **Reviewing and providing feedback on experimental APIs** to help improve their usability, consistency, and performance. | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /** | ||
| * @module SVG | ||
| * @submodule p5.svg | ||
| * @for p5 | ||
| */ | ||
|
|
||
| import { SVGExportAddon } from './svg_export.js'; | ||
| import { SVGImportAddon } from './svg_import.js'; | ||
| import { markExperimental } from '../../core/experimental.js'; | ||
|
|
||
| // Initializes the p5.js SVG module by combining export and import functionality. | ||
| // Registers public APIs on p5.prototype and marks experimental features with | ||
| // warning decorators to inform users about API stability during the 2.x lifecycle. | ||
| function svg(p5, fn, lifecycles) { | ||
| // Register core export (shape recording, vector output) and import (SVG parser) extensions. | ||
| SVGExportAddon(p5, fn, lifecycles); | ||
| SVGImportAddon(p5, fn, lifecycles); | ||
|
|
||
| // List of user-facing SVG methods marked as experimental. | ||
| // Decorators log friendly error warnings when these methods are invoked in user sketches. | ||
| const experimentalMethods = [ | ||
| 'createSVG', | ||
| 'loadSVG', | ||
| 'createShape', | ||
| 'buildShape', | ||
| 'getSVG', | ||
| 'shape', | ||
| 'saveSVG' | ||
| ]; | ||
|
|
||
| for (const method of experimentalMethods) { | ||
| if (fn[method]) { | ||
| p5.registerDecorator( | ||
| `p5.prototype.${method}`, | ||
| markExperimental('p5.svg', p5) | ||
| ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export default svg; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💟