feat: adiciona 12 plugins Descomplicar ao marketplace

Plugins: automacao, crm-ops, design-media, dev-tools, gestao,
infraestrutura, marketing, negocio, perfex-dev, project-manager,
wordpress + hello-plugin (existente).

Totais: 83 skills, 44 agents, 12 datasets.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 21:41:24 +00:00
parent bcce928beb
commit 2cb3210962
209 changed files with 50869 additions and 0 deletions

View File

@@ -0,0 +1,403 @@
---
name: maps
description: Make map animations with Mapbox
metadata:
tags: map, map animation, mapbox
---
Maps can be added to a Remotion video with Mapbox.
The [Mapbox documentation](https://docs.mapbox.com/mapbox-gl-js/api/) has the API reference.
## Prerequisites
Mapbox and `@turf/turf` need to be installed.
Search the project for lockfiles and run the correct command depending on the package manager:
If `package-lock.json` is found, use the following command:
```bash
npm i mapbox-gl @turf/turf @types/mapbox-gl
```
If `bun.lock` is found, use the following command:
```bash
bun i mapbox-gl @turf/turf @types/mapbox-gl
```
If `yarn.lock` is found, use the following command:
```bash
yarn add mapbox-gl @turf/turf @types/mapbox-gl
```
If `pnpm-lock.yaml` is found, use the following command:
```bash
pnpm i mapbox-gl @turf/turf @types/mapbox-gl
```
The user needs to create a free Mapbox account and create an access token by visiting https://console.mapbox.com/account/access-tokens/.
The mapbox token needs to be added to the `.env` file:
```txt title=".env"
REMOTION_MAPBOX_TOKEN==pk.your-mapbox-access-token
```
## Adding a map
Here is a basic example of a map in Remotion.
```tsx
import {useEffect, useMemo, useRef, useState} from 'react';
import {AbsoluteFill, useDelayRender, useVideoConfig} from 'remotion';
import mapboxgl, {Map} from 'mapbox-gl';
export const lineCoordinates = [
[6.56158447265625, 46.059891147620725],
[6.5691375732421875, 46.05679376154153],
[6.5842437744140625, 46.05059898938315],
[6.594886779785156, 46.04702502069337],
[6.601066589355469, 46.0460718554722],
[6.6089630126953125, 46.0365370783104],
[6.6185760498046875, 46.018420689207964],
];
mapboxgl.accessToken = process.env.REMOTION_MAPBOX_TOKEN as string;
export const MyComposition = () => {
const ref = useRef<HTMLDivElement>(null);
const {delayRender, continueRender} = useDelayRender();
const {width, height} = useVideoConfig();
const [handle] = useState(() => delayRender('Loading map...'));
const [map, setMap] = useState<Map | null>(null);
useEffect(() => {
const _map = new Map({
container: ref.current!,
zoom: 11.53,
center: [6.5615, 46.0598],
pitch: 65,
bearing: 0,
style: 'mapbox://styles/mapbox/standard',
interactive: false,
fadeDuration: 0,
});
_map.on('style.load', () => {
// Hide all features from the Mapbox Standard style
const hideFeatures = [
'showRoadsAndTransit',
'showRoads',
'showTransit',
'showPedestrianRoads',
'showRoadLabels',
'showTransitLabels',
'showPlaceLabels',
'showPointOfInterestLabels',
'showPointsOfInterest',
'showAdminBoundaries',
'showLandmarkIcons',
'showLandmarkIconLabels',
'show3dObjects',
'show3dBuildings',
'show3dTrees',
'show3dLandmarks',
'show3dFacades',
];
for (const feature of hideFeatures) {
_map.setConfigProperty('basemap', feature, false);
}
_map.setConfigProperty('basemap', 'colorMotorways', 'rgba(0, 0, 0, 0)');
_map.setConfigProperty('basemap', 'colorRoads', 'rgba(0, 0, 0, 0)');
_map.setConfigProperty('basemap', 'colorTrunks', 'rgba(0, 0, 0, 0)');
_map.addSource('trace', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: lineCoordinates,
},
},
});
_map.addLayer({
type: 'line',
source: 'trace',
id: 'line',
paint: {
'line-color': 'black',
'line-width': 5,
},
layout: {
'line-cap': 'round',
'line-join': 'round',
},
});
});
_map.on('load', () => {
continueRender(handle);
setMap(_map);
});
}, [handle, lineCoordinates]);
const style: React.CSSProperties = useMemo(() => ({width, height, position: 'absolute'}), [width, height]);
return <AbsoluteFill ref={ref} style={style} />;
};
```
The following is important in Remotion:
- Animations must be driven by `useCurrentFrame()` and animations that Mapbox brings itself should be disabled. For example, the `fadeDuration` prop should be set to `0`, `interactive` should be set to `false`, etc.
- Loading the map should be delayed using `useDelayRender()` and the map should be set to `null` until it is loaded.
- The element containing the ref MUST have an explicit width and height and `position: "absolute"`.
- Do not add a `_map.remove();` cleanup function.
## Drawing lines
Unless I request it, do not add a glow effect to the lines.
Unless I request it, do not add additional points to the lines.
## Map style
By default, use the `mapbox://styles/mapbox/standard` style.
Hide the labels from the base map style.
Unless I request otherwise, remove all features from the Mapbox Standard style.
```tsx
// Hide all features from the Mapbox Standard style
const hideFeatures = [
'showRoadsAndTransit',
'showRoads',
'showTransit',
'showPedestrianRoads',
'showRoadLabels',
'showTransitLabels',
'showPlaceLabels',
'showPointOfInterestLabels',
'showPointsOfInterest',
'showAdminBoundaries',
'showLandmarkIcons',
'showLandmarkIconLabels',
'show3dObjects',
'show3dBuildings',
'show3dTrees',
'show3dLandmarks',
'show3dFacades',
];
for (const feature of hideFeatures) {
_map.setConfigProperty('basemap', feature, false);
}
_map.setConfigProperty('basemap', 'colorMotorways', 'transparent');
_map.setConfigProperty('basemap', 'colorRoads', 'transparent');
_map.setConfigProperty('basemap', 'colorTrunks', 'transparent');
```
## Animating the camera
You can animate the camera along the line by adding a `useEffect` hook that updates the camera position based on the current frame.
Unless I ask for it, do not jump between camera angles.
```tsx
import * as turf from '@turf/turf';
import {interpolate} from 'remotion';
import {Easing} from 'remotion';
import {useCurrentFrame, useVideoConfig, useDelayRender} from 'remotion';
const animationDuration = 20;
const cameraAltitude = 4000;
```
```tsx
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const {delayRender, continueRender} = useDelayRender();
useEffect(() => {
if (!map) {
return;
}
const handle = delayRender('Moving point...');
const routeDistance = turf.length(turf.lineString(lineCoordinates));
const progress = interpolate(frame / fps, [0.00001, animationDuration], [0, 1], {
easing: Easing.inOut(Easing.sin),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const camera = map.getFreeCameraOptions();
const alongRoute = turf.along(turf.lineString(lineCoordinates), routeDistance * progress).geometry.coordinates;
camera.lookAtPoint({
lng: alongRoute[0],
lat: alongRoute[1],
});
map.setFreeCameraOptions(camera);
map.once('idle', () => continueRender(handle));
}, [lineCoordinates, fps, frame, handle, map]);
```
Notes:
IMPORTANT: Keep the camera by default so north is up.
IMPORTANT: For multi-step animations, set all properties at all stages (zoom, position, line progress) to prevent jumps. Override initial values.
- The progress is clamped to a minimum value to avoid the line being empty, which can lead to turf errors
- See [Timing](./timing.md) for more options for timing.
- Consider the dimensions of the composition and make the lines thick enough and the label font size large enough to be legible for when the composition is scaled down.
## Animating lines
### Straight lines (linear interpolation)
To animate a line that appears straight on the map, use linear interpolation between coordinates. Do NOT use turf's `lineSliceAlong` or `along` functions, as they use geodesic (great circle) calculations which appear curved on a Mercator projection.
```tsx
const frame = useCurrentFrame();
const {durationInFrames} = useVideoConfig();
useEffect(() => {
if (!map) return;
const animationHandle = delayRender('Animating line...');
const progress = interpolate(frame, [0, durationInFrames - 1], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.inOut(Easing.cubic),
});
// Linear interpolation for a straight line on the map
const start = lineCoordinates[0];
const end = lineCoordinates[1];
const currentLng = start[0] + (end[0] - start[0]) * progress;
const currentLat = start[1] + (end[1] - start[1]) * progress;
const lineData: GeoJSON.Feature<GeoJSON.LineString> = {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: [start, [currentLng, currentLat]],
},
};
const source = map.getSource('trace') as mapboxgl.GeoJSONSource;
if (source) {
source.setData(lineData);
}
map.once('idle', () => continueRender(animationHandle));
}, [frame, map, durationInFrames]);
```
### Curved lines (geodesic/great circle)
To animate a line that follows the geodesic (great circle) path between two points, use turf's `lineSliceAlong`. This is useful for showing flight paths or the actual shortest distance on Earth.
```tsx
import * as turf from '@turf/turf';
const routeLine = turf.lineString(lineCoordinates);
const routeDistance = turf.length(routeLine);
const currentDistance = Math.max(0.001, routeDistance * progress);
const slicedLine = turf.lineSliceAlong(routeLine, 0, currentDistance);
const source = map.getSource('route') as mapboxgl.GeoJSONSource;
if (source) {
source.setData(slicedLine);
}
```
## Markers
Add labels, and markers where appropriate.
```tsx
_map.addSource('markers', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {name: 'Point 1'},
geometry: {type: 'Point', coordinates: [-118.2437, 34.0522]},
},
],
},
});
_map.addLayer({
id: 'city-markers',
type: 'circle',
source: 'markers',
paint: {
'circle-radius': 40,
'circle-color': '#FF4444',
'circle-stroke-width': 4,
'circle-stroke-color': '#FFFFFF',
},
});
_map.addLayer({
id: 'labels',
type: 'symbol',
source: 'markers',
layout: {
'text-field': ['get', 'name'],
'text-font': ['DIN Pro Bold', 'Arial Unicode MS Bold'],
'text-size': 50,
'text-offset': [0, 0.5],
'text-anchor': 'top',
},
paint: {
'text-color': '#FFFFFF',
'text-halo-color': '#000000',
'text-halo-width': 2,
},
});
```
Make sure they are big enough. Check the composition dimensions and scale the labels accordingly.
For a composition size of 1920x1080, the label font size should be at least 40px.
IMPORTANT: Keep the `text-offset` small enough so it is close to the marker. Consider the marker circle radius. For a circle radius of 40, this is a good offset:
```tsx
"text-offset": [0, 0.5],
```
## 3D buildings
To enable 3D buildings, use the following code:
```tsx
_map.setConfigProperty('basemap', 'show3dObjects', true);
_map.setConfigProperty('basemap', 'show3dLandmarks', true);
_map.setConfigProperty('basemap', 'show3dBuildings', true);
```
## Rendering
When rendering a map animation, make sure to render with the following flags:
```
npx remotion render --gl=angle --concurrency=1
```