Beautiful hand-drawn animations for Laravel. A lightweight Rough Notation wrapper to circle, underline, and highlight elements in your Blade and Livewire applications.
- Fluent
Notation::builder for creating annotations - Blade directives:
@annotate,@endannotate, and@roughNotationScripts - Supports types: underline, box, circle, highlight, strike-through, crossed-off, bracket
- Options: color, strokeWidth, padding, iterations, brackets, animationDuration
- Group multiple annotations to animate in sequence
composer require amjadiqbal/laravel-rough-notationRun the guided installer:
php artisan rough:installOptions:
- --cdn=true|false to select CDN vs local
- --publish-assets=true|false to download local ESM script
- --assets-path=public/vendor/rough-notation to pick destination path
- --open-link=true to open support/contact page
Example:
php artisan rough:install --cdn=false --publish-assets=true --assets-path=public/vendor/rough-notationPublish the package config:
php artisan vendor:publish --tag=rough-notation-configPublish local ESM script:
php artisan rough:publish-assets --path=public/vendor/rough-notation- Install:
composer require amjadiqbal/laravel-rough-notation - Guided install:
php artisan rough:install - Publish config:
php artisan vendor:publish --tag=rough-notation-config - Publish local ESM:
php artisan rough:publish-assets --path=public/vendor/rough-notation - Add scripts:
@roughNotationScripts - Annotate with directives, components, or the builder API
Add scripts to your layout:
@roughNotationScriptsConfiguration (optional) published to config/rough-notation.php:
return [
'assets' => [
'cdn' => true,
'module_url' => 'https://unpkg.com/rough-notation?module',
'local' => [
'public_url' => '/vendor/rough-notation',
'module' => 'rough-notation.esm.js',
],
],
];- PHP 8.1+
- Laravel 11
<!-- resources/views/layouts/app.blade.php -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rough Notation Demo</title>
</head>
<body>
@yield('content')
@roughNotationScripts
</body>
</html>Wrap any text or element:
@annotate('circle', ['color' => '#ff0055']) Important Text @endannotateWith options:
@annotate('highlight', ['color' => '#fff59d', 'padding' => 6]) Highlighted @endannotateGroups:
@annotate('underline', [], 'hero') First @endannotate
@annotate('box', ['padding' => 8], 'hero') Second @endannotate
@annotate('circle', ['color' => 'red'], 'hero') Third @endannotateuse AmjadIqbal\RoughNotation\Notation;
echo Notation::make('circle')
->color('red')
->strokeWidth(3)
->group('hero')
->render('Important Text');Basic component:
<x-annotate type="circle" :options="['color' => 'red']">Important</x-annotate>Typed components (namespaced):
<x-rough-notation::circle :options="['color' => 'red']">Circled</x-rough-notation::circle>
<x-rough-notation::underline>Underlined</x-rough-notation::underline>
<x-rough-notation::box :options="['padding' => 8]">Boxed</x-rough-notation::box>
<x-rough-notation::highlight :options="['color' => '#fff59d']">Highlighted</x-rough-notation::highlight>
<x-rough-notation::strike-through>Struck</x-rough-notation::strike-through>
<x-rough-notation::crossed-off>Crossed</x-rough-notation::crossed-off>
<x-rough-notation::bracket :options="['brackets' => ['left','right']]">Bracketed</x-rough-notation::bracket>Props:
- options: array of supported options
- group: string group id to sequence annotations
- tag: wrapper tag (defaults to span)
// routes/web.php
use Illuminate\Support\Facades\Route;
Route::view('/rough-demo', 'rough-demo');<!-- resources/views/rough-demo.blade.php -->
@extends('layouts.app')
@section('content')
<div style="display:grid; gap:16px; padding:24px;">
@annotate('underline') Underline @endannotate
@annotate('box', ['padding' => 8]) Boxed @endannotate
@annotate('circle', ['color' => 'red']) Circled @endannotate
@annotate('highlight', ['color' => '#fff59d']) Highlighted @endannotate
@annotate('strike-through') Struck @endannotate
@annotate('crossed-off') Crossed @endannotate
@annotate('bracket', ['brackets' => ['left','right']]) Bracketed @endannotate
@annotate('underline', [], 'hero') Step 1 @endannotate
@annotate('box', ['padding' => 8], 'hero') Step 2 @endannotate
@annotate('circle', ['color' => 'red'], 'hero') Step 3 @endannotate
</div>
@endsectionEach example shows the directive and a short description.
- underline:
@annotate('underline') Underline @endannotate
- box:
@annotate('box', ['padding' => 8]) Boxed @endannotate
- circle:
@annotate('circle', ['color' => 'red']) Circled @endannotate
- highlight:
@annotate('highlight', ['color' => '#fff59d']) Highlighted @endannotate
- strike-through:
@annotate('strike-through') Struck @endannotate
- crossed-off:
@annotate('crossed-off') Crossed @endannotate
- bracket:
@annotate('bracket', ['brackets' => ['left', 'right']]) Bracketed @endannotate
- The scripts directive auto re-initializes after Livewire updates.
- For manual re-init:
window.initRoughNotation();vendor/bin/pest- Livewire: call
window.initRoughNotation()after component updates to re-init annotations on dynamic content. - Multiple groups: mix sequences by assigning different group ids to elements.
- Local assets: after
php artisan rough:publish-assets, setcdntofalsein config to import the local ESM.
- color: string color or hex
- strokeWidth: int line width
- padding: int inner padding in px
- iterations: int number of sketch strokes
- animationDuration: int in ms
- brackets: array|string (left|right|top|bottom) only for type=bracket
- Follow PSR-12 code style
- Run tests before submitting changes
- Open a PR with a clear description
MIT License. See LICENSE.




