vizor-vr/laravel-vizor

Laravel Livewire components for the Vizor VR video player

Maintainers

Package info

github.com/vizor-vr/laravel-vizor

pkg:composer/vizor-vr/laravel-vizor

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-06-29 17:00 UTC

This package is auto-updated.

Last update: 2026-06-29 18:39:53 UTC


README

Latest Version on Packagist Laravel 11+/12+ PHP 8.2+ Tests License: MIT

Laravel package for the Vizor VR video player. Provides 7 Blade components, 6 Livewire components with reactive state, an Alpine.js plugin, a full API facade, Filament admin integration, license validation middleware, and a Tailwind CSS preset -- everything you need to embed 360/VR/WebXR video in a Laravel application.

Requirements

  • PHP 8.2+
  • Laravel 11 or 12
  • Livewire 3+

Installation

composer require vizor-vr/laravel-vizor
php artisan vizor:install

The install command publishes the config file, the Alpine.js plugin, and generates a test page at /vizor-test.

Quick Start

1. Install the package

composer require vizor-vr/laravel-vizor
php artisan vizor:install

2. Add environment variables

VIZOR_API_KEY=your-api-key
VIZOR_LICENSE_KEY=your-license-key

3. Use a Blade component

<x-vizor-video
    src="/videos/tour.mp4"
    :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
    title="My VR Video"
/>

Visit /vizor-test to verify the player renders correctly.

Blade Components

All 7 components auto-include the player script via @vizorScripts and accept an optional {{ $slot }} for child elements.

Component Element Use case
<x-vizor-video> <vz-video> 360/VR/flat video
<x-vizor-img> <vz-img> 360/VR images
<x-vizor-tour> <vz-tour> Multi-scene virtual tours
<x-vizor-cinema> <vz-cinema> Virtual cinema environment
<x-vizor-live> <vz-live> Live HLS/DASH streams
<x-vizor-playlist> <vz-playlist> Multi-video playlist
<x-vizor-annotation> <vz-annotation> Spatial annotations (nested inside video)

Video

<x-vizor-video
    src="/videos/ocean.mp4"
    :format="\Vizor\Laravel\Support\FormatEnum::STEREO_360_TB"
    title="Ocean Dive"
    poster="/images/ocean-thumb.jpg"
    :autoplay="true"
    :loop="true"
/>

Image

<x-vizor-img
    src="/images/panorama.jpg"
    :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
    title="Mountain Panorama"
/>

Tour

<x-vizor-tour
    src="/tours/apartment.json"
    title="Apartment Tour"
    start-probe-id="living-room"
/>

Cinema

<x-vizor-cinema
    src="/videos/movie.mp4"
    :format="\Vizor\Laravel\Support\FormatEnum::MONO_FLAT"
    title="Feature Film"
/>

Live Stream

<x-vizor-live
    src="https://stream.example.com/live.m3u8"
    :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
    title="Live Concert"
/>

Playlist

<x-vizor-playlist :autoplay="true" :loop-playlist="true">
    <x-vizor-video
        src="/videos/clip-1.mp4"
        :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
        title="Clip 1"
    />
    <x-vizor-video
        src="/videos/clip-2.mp4"
        :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
        title="Clip 2"
    />
</x-vizor-playlist>

Annotations

Nest <x-vizor-annotation> inside a video component to place 3D hotspots:

<x-vizor-video
    src="/videos/tour.mp4"
    :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
>
    <x-vizor-annotation
        :lat="15.5"
        :lon="-42.3"
        title="Look here"
        icon="info"
        :time-start="10.0"
        :time-end="30.0"
    />
</x-vizor-video>

Livewire Components

Full server-side reactive state with two-way binding. All components use the HasVizorEvents and HasVizorProps traits.

Livewire Tag Reactive State
<livewire:vizor-video-player> currentTime, duration, volume, playing, isMuted, fullscreen, ready
<livewire:vizor-img-viewer> ready
<livewire:vizor-tour-viewer> ready, currentProbeId
<livewire:vizor-cinema-player> currentTime, duration, volume, playing, isMuted, ready
<livewire:vizor-live-player> playing, ready, volume, isMuted
<livewire:vizor-playlist-player> currentIndex, currentTitle, totalItems, playing, ready

Usage

<livewire:vizor-video-player
    src="/videos/ocean.mp4"
    :format="\Vizor\Laravel\Support\FormatEnum::MONO_360"
    title="Ocean Dive"
/>

Server-Side Control

All video-based Livewire components expose play(), pause(), and seek() methods you can call from other Livewire components or from Blade:

<livewire:vizor-video-player wire:ref="player" src="/video.mp4" />

<button wire:click="$refs.player.play()">Play</button>
<button wire:click="$refs.player.pause()">Pause</button>

Generating Custom Components

Scaffold a new Livewire component with Vizor boilerplate:

php artisan vizor:component MyCustomPlayer

This creates app/Livewire/MyCustomPlayer.php and resources/views/livewire/my-custom-player.blade.php with the full event handler scaffold.

Alpine.js Plugin

For projects that don't use Livewire, the Alpine.js plugin provides client-side reactive bindings with no server round-trips.

Setup

Register the plugin in your resources/js/app.js:

import Alpine from 'alpinejs';
import vizorAlpine from './vizor-alpine.js';

Alpine.plugin(vizorAlpine);
Alpine.start();

Usage

<div x-data="vizorPlayer">
    <vz-video
        x-ref="player"
        src="/videos/ocean.mp4"
        format="MONO_360"
    ></vz-video>

    <button @click="togglePlay" x-text="playing ? 'Pause' : 'Play'"></button>
    <span x-text="`${Math.floor(currentTime)}s / ${Math.floor(duration)}s`"></span>
</div>

The vizorPlayer data component exposes: ready, playing, currentTime, duration, volume, muted, fullscreen, loading, error -- plus methods play(), pause(), togglePlay(), seek(t), toggleMute(), setVolume(v), enterFullscreen(), exitFullscreen().

Vizor Facade

The Vizor facade provides typed access to the Vizor REST API. It is backed by the VizorManager class and configured via VIZOR_API_KEY and VIZOR_API_URL.

Content

use Vizor\Laravel\Facades\Vizor;

// List content
$items = Vizor::content()->list(search: 'ocean', limit: 10);

// CRUD
$item = Vizor::content()->create('New Video', 'MONO_360', ['src' => '...']);
$item = Vizor::content()->get($id);
Vizor::content()->update($id, ['title' => 'Updated Title']);
Vizor::content()->delete($id);

Analytics

$overview   = Vizor::analytics()->overview(days: 30);
$views      = Vizor::analytics()->viewsOverTime(days: 7);
$top        = Vizor::analytics()->topContent(days: 30, limit: 5);
$engagement = Vizor::analytics()->engagement(days: 30);
$summary    = Vizor::analytics()->contentSummary($contentId);
$gaze       = Vizor::analytics()->gazeData($contentId);

API Keys

$keys = Vizor::apiKeys()->list();
$key  = Vizor::apiKeys()->create('Production Key', domains: ['example.com']);
$valid = Vizor::apiKeys()->validate($keyString); // bool
Vizor::apiKeys()->revoke($id);

License Keys

$keys  = Vizor::licenseKeys()->list();
$key   = Vizor::licenseKeys()->generate(domains: ['example.com'], tier: 'pro');
$valid = Vizor::licenseKeys()->validate($keyString); // bool
Vizor::licenseKeys()->revoke($id);

Billing

$status = Vizor::billing()->status();
$plans  = Vizor::billing()->plans();

Artisan Commands

Command Description
vizor:install Publish config, Alpine plugin, prompt for API key, generate test page
vizor:component {name} Scaffold a Livewire component with Vizor boilerplate
vizor:test-page Create a test page with all player types at /vizor-test
vizor:examples Publish 3 example components (VideoPlayer, VideoGallery, AnalyticsDashboard)

All commands accept --force to overwrite existing files.

Middleware

The vizor.license middleware validates your license key against the Vizor API (with cache). On failure it degrades the tier to free (watermark, mono only) rather than blocking the request.

Route Group

Route::middleware('vizor.license')->group(function () {
    Route::get('/vr/{id}', [VrController::class, 'show']);
});

Configuration

VIZOR_VALIDATE_LICENSE=true
VIZOR_LICENSE_MODE=saas          # "saas" (validates API key) or "standalone" (validates license key)
VIZOR_LICENSE_CACHE_TTL=3600     # seconds to cache validation result

Filament Integration

The package includes a Filament v3 plugin with a content resource and an embeddable player widget.

Setup

Enable in your .env:

VIZOR_FILAMENT=true

Register the plugin in your panel provider:

use Vizor\Laravel\Filament\VizorPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            VizorPlugin::make(),
        ]);
}

This adds:

  • Content Resource -- full CRUD table for Vizor content
  • Player Widget -- embeddable VR player widget for dashboards

Broadcasting

Optionally broadcast player events (play, pause, ended, ready, error, timeupdate) over Laravel Echo for real-time dashboards or collaborative features.

Enable

VIZOR_BROADCASTING=true

Listen

Echo.channel('vizor.content-id-123')
    .listen('PlayerPlay', (e) => console.log('Playing', e))
    .listen('PlayerPause', (e) => console.log('Paused', e))
    .listen('PlayerEnded', (e) => console.log('Ended', e));

Events broadcast: PlayerReady, PlayerPlay, PlayerPause, PlayerEnded, PlayerError, PlayerTimeUpdate.

Tailwind CSS Preset

Import the preset in your tailwind.config.js for Vizor-specific utilities:

import vizorPreset from './vendor/vizor-vr/laravel-vizor/tailwind.preset.js';

export default {
    presets: [vizorPreset],
    // ...
};

Included utilities

Class Description
vizor-container 16:9 aspect ratio, full width, relative positioned
vizor-container-4k Same as above, max 3840px, centered
vizor-rounded 0.75rem border radius with overflow hidden
vizor-shadow VR player drop shadow
vizor-loading Dark pulsing loading placeholder
text-vizor-primary Primary brand color (CSS variable --vizor-primary)
aspect-vizor 16:9 aspect ratio
aspect-vizor-square 1:1 aspect ratio
max-w-vizor-1080 Max width 1920px
Responsive: vizor-sm, vizor-md, vizor-lg, vizor-xl Breakpoints at 480/768/1024/1440px

Configuration Reference

Publish the config file with php artisan vendor:publish --tag=vizor-config.

Config Key Env Variable Default Description
api_url VIZOR_API_URL https://api.vizor-vr.com Vizor API base URL
api_key VIZOR_API_KEY null Your Vizor API key
license_key VIZOR_LICENSE_KEY null Standalone license key
license_mode VIZOR_LICENSE_MODE saas saas or standalone
cdn_url VIZOR_CDN_URL https://cdn.jsdelivr.net/npm/@vizor-vr/player@latest/dist Player script CDN URL
player_version VIZOR_PLAYER_VERSION 0.1.0 Player version
use_local_assets VIZOR_USE_LOCAL_ASSETS false Serve player JS from local assets
default_format -- MONO_360 Default projection format
default_controls -- true Show controls by default
default_muted -- false Start muted by default
primary_color VIZOR_PRIMARY_COLOR #f43f5e Brand primary color
brand_name VIZOR_BRAND_NAME null Custom brand name
brand_logo VIZOR_BRAND_LOGO null Custom brand logo URL
validate_license VIZOR_VALIDATE_LICENSE true Enable license validation
license_cache_ttl VIZOR_LICENSE_CACHE_TTL 3600 License cache duration (seconds)
broadcasting.enabled VIZOR_BROADCASTING false Enable event broadcasting
broadcasting.channel_prefix -- vizor Echo channel prefix
filament.enabled VIZOR_FILAMENT false Enable Filament integration
filament.navigation_group -- Vizor Filament nav group label

Publishable Assets

php artisan vendor:publish --tag=vizor-config      # config/vizor.php
php artisan vendor:publish --tag=vizor-assets       # resources/js/vizor-alpine.js
php artisan vendor:publish --tag=vizor-views        # Blade views
php artisan vendor:publish --tag=vizor-migrations   # Database migrations

Supported Formats

The FormatEnum enum covers all 19 projection formats:

Full format list
Enum Value Label
MONO_360 Mono 360
MONO_FLAT Mono Flat
STEREO_180_LR Stereo 180 Side-by-Side
STEREO_180_TB Stereo 180 Top-Bottom
STEREO_180_LR_SPHERICAL VR180 Side-by-Side
STEREO_180_TB_SPHERICAL VR180 Top-Bottom
STEREO_360_LR Stereo 360 Side-by-Side
STEREO_360_TB Stereo 360 Top-Bottom
STEREO_FLAT_LR Stereo Flat Side-by-Side
STEREO_FLAT_LR_SQUARE Stereo Flat SBS Square
STEREO_FLAT_TB Stereo Flat Top-Bottom
STEREO_FLAT_TB_SQUARE Stereo Flat TB Square
MONO_CUBEMAP Mono Cubemap
STEREO_CUBEMAP Stereo Cubemap
MONO_EAC Mono EAC
STEREO_EAC_TB Stereo EAC Top-Bottom
MONO_FISHEYE Mono Fisheye
STEREO_FISHEYE_LR Stereo Fisheye Side-by-Side
CARDBOARD_PHOTO Cardboard Photo

Testing

The package uses Pest with both unit and feature tests.

vendor/bin/pest

Tests cover: service provider registration, Blade components, Livewire components, Facade API client, middleware, commands, broadcasting, Filament plugin, Tailwind preset, config, enums, and traits.

Changelog

See CHANGELOG.md for release history.

License

The MIT License (MIT). See LICENSE for details.