Migration Guide
Migration Guide: 0.3.x to 0.4.x
Overview
Version 0.4.0 migrates the physics engine from Forge2D (Box2D) to Chipmunk2D. The public API remains compatible, so most users won't need to make any code changes. However, there are a few important points to be aware of.
What Changed
- Physics Engine: The underlying physics engine has been changed from Forge2D to Chipmunk2D
- Dependency: The package no longer depends on
forge2dand now useschipmunk2d_physics_ffiinstead - API Compatibility: The public API remains the same - your existing code should work without changes
Migration Steps
-
Update your dependency:
dependencies:
newton_particles: ^0.4.0 -
Remove any direct
forge2ddependencies (if you have any): If your project directly depends onforge2d, you'll need to remove it as it's no longer used by Newton. -
Run
flutter pub get:flutter pub get -
Initialize Newton (Required on web for physics effects):
On web, you must initialize Newton before using any physics-based effects. On other platforms, this is optional (no-op). Add the initialization to your app's
main()function for cross-platform compatibility:import 'package:flutter/material.dart';
import 'package:newton_particles/newton_particles.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeNewton();
runApp(MyApp());
}Note:
- On web, this initialization is required if you're using
PhysicsEffectConfiguration. - On other platforms (iOS, Android, macOS, Linux, Windows), this is a no-op and can be safely called or omitted.
- If you're only using
DeterministicEffectConfiguration, you can skip this step on all platforms.
- On web, this initialization is required if you're using
-
Add dynamic import helper for web (Required for WASM on web):
If you're building for web with WASM and using physics effects, you need to add a helper script to your
web/index.htmlfile. Add this script before theflutter_bootstrap.jsscript:<body>
<script>
window._dynamicImport = (path) => import(path);
</script>
<script src="flutter_bootstrap.js" async></script>
</body>This helper is required for Chipmunk2D's WASM module to load properly on web.
-
Test your physics effects: While the API is compatible, the underlying physics engine behaves slightly differently. Test your physics-based effects to ensure they behave as expected.
What to Expect
- Better Performance: Chipmunk2D generally provides better performance, especially for large numbers of particles
- Same Behavior: Physics simulations should behave similarly, though there may be minor differences due to different physics engines
- All Features Preserved: All existing features (collisions, gravity, density, friction, restitution, etc.) continue to work as before
Breaking Changes
- If you were directly importing or using Forge2D classes from the Newton package, those are no longer available
- The internal physics world implementation has changed, but this shouldn't affect your code unless you were accessing internal classes
Need Help?
If you encounter any issues during migration:
- Check that you've updated to
^0.4.0 - Ensure you've run
flutter pub get - Review the changelog for detailed changes
- Open an issue on GitHub
Migration Guide: 0.2.x to 0.3.x
This guide will help you migrate your Newton particle effects from version 0.2.x to 0.3.x. The new version introduces a more organized API using grouped properties, which provides better type safety and code organization.
Overview of Changes
Breaking Changes
-
RelativisticEffectConfigurationrenamed toPhysicsEffectConfiguration- The class name has been changed to better reflect its purpose.
-
activeEffectsparameter renamed toeffectConfigurations- The
Newtonwidget now useseffectConfigurationsinstead ofactiveEffects.
- The
-
Properties are now grouped into dedicated classes
- Individual properties are now organized into grouped property classes for better organization and validation.
Step-by-Step Migration
1. Update Newton Widget Parameter
Before (0.2.x):
Newton(
activeEffects: [
// effects...
],
)
After (0.3.x):
Newton(
effectConfigurations: [
// effects...
],
)
2. Rename RelativisticEffectConfiguration
Before (0.2.x):
RelativisticEffectConfiguration(
// properties...
)
After (0.3.x):
PhysicsEffectConfiguration(
// properties...
)
3. Migrate Properties to Grouped Classes
The biggest change is that properties are now organized into grouped classes. Here's how to migrate:
Physics-Based Effects
Before (0.2.x):
RelativisticEffectConfiguration(
gravity: Gravity.earthGravity,
minAngle: 90,
maxAngle: 90,
minVelocity: Velocity.stationary,
maxVelocity: Velocity.stationary,
minEndScale: 1,
maxEndScale: 1,
minFadeOutThreshold: 0.6,
maxFadeOutThreshold: 0.8,
origin: Offset.zero,
maxOriginOffset: Offset(1, 0),
minParticleLifespan: Duration(seconds: 7),
maxParticleLifespan: Duration(seconds: 10),
particleConfiguration: ParticleConfiguration(...),
)
After (0.3.x):
PhysicsEffectConfiguration(
physicsProperties: PhysicsProperties(
gravity: Gravity.earthGravity,
angle: NumRange.single(90),
velocity: NumRange.between(Velocity.stationary, Velocity.stationary),
),
visualProperties: VisualProperties(
endScale: NumRange.single(1),
fadeOutThreshold: NumRange.between(0.6, 0.8),
),
emissionProperties: EmissionProperties(
origin: Offset.zero,
maxOriginOffset: Offset(1, 0),
particleLifespan: DurationRange.between(Duration(seconds: 7), Duration(seconds: 10)),
),
particleConfiguration: ParticleConfiguration(...),
)
Deterministic Effects
Before (0.2.x):
DeterministicEffectConfiguration(
minAngle: 90,
maxAngle: 90,
minDistance: 200,
maxDistance: 200,
minEndScale: 1,
maxEndScale: 1,
minFadeOutThreshold: 0.6,
maxFadeOutThreshold: 0.8,
origin: Offset.zero,
maxOriginOffset: Offset(1, 0),
minParticleLifespan: Duration(seconds: 4),
maxParticleLifespan: Duration(seconds: 7),
particleConfiguration: ParticleConfiguration(...),
)
After (0.3.x):
DeterministicEffectConfiguration(
deterministicProperties: DeterministicProperties(
angle: NumRange.single(90),
distance: NumRange.single(200),
),
visualProperties: VisualProperties(
endScale: NumRange.single(1),
fadeOutThreshold: NumRange.between(0.6, 0.8),
),
emissionProperties: EmissionProperties(
origin: Offset.zero,
maxOriginOffset: Offset(1, 0),
particleLifespan: DurationRange.between(Duration(seconds: 4), Duration(seconds: 7)),
),
particleConfiguration: ParticleConfiguration(...),
)
Property Group Mapping
PhysicsProperties
Groups all physics-related properties:
gravity→physicsProperties.gravityminAngle/maxAngle→physicsProperties.angle: NumRange.between(min, max)orNumRange.single(value)minVelocity/maxVelocity→physicsProperties.velocity: NumRange.between(min, max)minDensity/maxDensity→physicsProperties.density: NumRange.between(min, max)minFriction/maxFriction→physicsProperties.friction: NumRange.between(min, max)minRestitution/maxRestitution→physicsProperties.restitution: NumRange.between(min, max)onlyInteractWithEdges→physicsProperties.onlyInteractWithEdgessolidEdges→physicsProperties.solidEdges
VisualProperties
Groups all visual appearance properties:
minEndScale/maxEndScale→visualProperties.endScale: NumRange.between(min, max)orNumRange.single(value)minFadeInThreshold/maxFadeInThreshold→visualProperties.fadeInThreshold: NumRange.between(min, max)minFadeOutThreshold/maxFadeOutThreshold→visualProperties.fadeOutThreshold: NumRange.between(min, max)scaleCurve→visualProperties.scaleCurvefadeInCurve→visualProperties.fadeInCurvefadeOutCurve→visualProperties.fadeOutCurve
EmissionProperties
Groups all emission-related properties. Note: EmissionProperties is now
part of the base EffectConfiguration class, making it available to both
PhysicsEffectConfiguration and DeterministicEffectConfiguration:
origin→emissionProperties.originminOriginOffset/maxOriginOffset→emissionProperties.minOriginOffset/maxOriginOffsetparticleCount→emissionProperties.particleCountparticlesPerEmit→emissionProperties.particlesPerEmitemitDuration→emissionProperties.emitDurationemitCurve→emissionProperties.emitCurveminParticleLifespan/maxParticleLifespan→emissionProperties.particleLifespan: DurationRange.between(min, max)
DeterministicProperties
Groups deterministic-specific properties:
minAngle/maxAngle→deterministicProperties.angle: NumRange.between(min, max)minDistance/maxDistance→deterministicProperties.distance: NumRange.between(min, max)
AnimationProperties
Groups animation timing properties:
startDelay→animationProperties.startDelay
LayerProperties
Groups layer and trail properties:
particleLayer→layerProperties.particleLayertrail→layerProperties.trail
Using Range Helpers
The new API uses NumRange and DurationRange objects for min/max values. Use
these helpers:
NumRange.single(value)- For a single numeric value (no variation)NumRange.between(min, max)- For a numeric range between min and maxDurationRange.single(Duration(...))- For a single duration valueDurationRange.between(Duration(...), Duration(...))- For a duration range
Example:
// Single numeric value
endScale: NumRange.single(1)
// Numeric range
fadeOutThreshold: NumRange.between(0.6, 0.8)
velocity: NumRange.between(Velocity.custom(3), Velocity.custom(5))
// Duration range
particleLifespan: DurationRange.between(Duration(seconds: 3), Duration(seconds: 5))
Configuration Overrider Changes
If you're using configurationOverrider (formerly effectOverrider), update
the copyWith call:
Before (0.2.x):
configurationOverrider: (effect) {
return effect.effectConfiguration.copyWith(
physicsProperties: effect.effectConfiguration.physicsProperties.copyWith(
angle: NumRange.single(angle),
),
);
}
After (0.3.x):
configurationOverrider: (effect) {
return effect.effectConfiguration.copyWith(
physicsProperties: effect.effectConfiguration.physicsProperties.copyWith(
angle: NumRange.single(angle),
),
);
}
Post Effect Builder Changes
When creating post effects in postEffectBuilder, use the new API:
Before (0.2.x):
postEffectBuilder: (particle, effect) {
return PhysicsEffectConfiguration(
physicsProperties: const PhysicsProperties(
gravity: Gravity.earthGravity,
angle: NumRange.between(-180, 180),
// ... other properties
);
}
After (0.3.x):
postEffectBuilder: (particle, effect) {
return PhysicsEffectConfiguration(
physicsProperties: const PhysicsProperties(
gravity: Gravity.earthGravity,
angle: NumRange.between(-180, 180),
),
// ... other grouped properties
);
}
Benefits of the New API
-
Better Organization: Properties are logically grouped, making configurations easier to understand and maintain.
-
Type Safety: Grouped properties provide better validation and type checking.
-
Consistency: Both physics and deterministic effects use similar property grouping patterns.
-
Extensibility: New properties can be added to appropriate groups without cluttering the main configuration class.
Common Patterns
Rain Effect Migration
Before:
RelativisticEffectConfiguration(
gravity: Gravity.earthGravity,
minAngle: 90,
maxAngle: 90,
minVelocity: Velocity.stationary,
maxVelocity: Velocity.stationary,
origin: Offset.zero,
maxOriginOffset: Offset(1, 0),
minParticleLifespan: Duration(seconds: 7),
maxParticleLifespan: Duration(seconds: 10),
particleConfiguration: ParticleConfiguration(...),
)
After:
PhysicsEffectConfiguration(
physicsProperties: const PhysicsProperties(
gravity: Gravity.earthGravity,
angle: NumRange.single(90),
velocity: NumRange.between(Velocity.stationary, Velocity.stationary),
),
emissionProperties: const EmissionProperties(
origin: Offset.zero,
maxOriginOffset: Offset(1, 0),
particleLifespan: DurationRange.between(Duration(seconds: 7), Duration(seconds: 10)),
),
particleConfiguration: ParticleConfiguration(...),
)
Need Help?
If you encounter issues during migration, please:
- Check the updated documentation
- Review the effect samples for examples
- Open an issue on GitHub