This commit is contained in:
th committed 2026-04-19 19:07:51 +02:00
1 parent c6863f2bfc
commit 94e9846c13
11 files changed
+985 -136

No files matched your search

+94 -34
View File
@@ -1,8 +1,9 @@
import type { Scene } from '@/types/scene'
const RUNTIME_SOURCE = `(function(){
var SCENE = __SCENE__;
var OPTIONS = __OPTIONS__;
const RUNTIME_VERSION = '1'
const ENGINE_SOURCE = `(function(){
if (window.AnimatrPlayer && window.AnimatrPlayer.__v === '${RUNTIME_VERSION}') return;
function easing(name, t){
if(name==='easeIn')return t*t;
@@ -156,15 +157,19 @@ const RUNTIME_SOURCE = `(function(){
ctx.fillStyle=p.fill||asset.fill;
ctx.fillRect(-rOffX,-rOffY,asset.width,asset.height);
}else if(asset.kind==='circle'){
var cOffX=layer.offsetX!=null?layer.offsetX:0;
var cOffY=layer.offsetY!=null?layer.offsetY:0;
ctx.fillStyle=p.fill||asset.fill;
ctx.beginPath();
ctx.arc(0,0,asset.radius,0,Math.PI*2);
ctx.arc(-cOffX,-cOffY,asset.radius,0,Math.PI*2);
ctx.fill();
}else if(asset.kind==='text'){
var tOffX=layer.offsetX!=null?layer.offsetX:0;
var tOffY=layer.offsetY!=null?layer.offsetY:0;
ctx.fillStyle=p.fill||asset.fill;
ctx.font=asset.fontSize+'px sans-serif';
ctx.textBaseline='top';
ctx.fillText(asset.text,0,0);
ctx.fillText(asset.text,-tOffX,-tOffY);
}else if(asset.kind==='image'){
var img=imgs[asset.id];
if(img){
@@ -183,22 +188,33 @@ const RUNTIME_SOURCE = `(function(){
});
}
var script=document.currentScript;
var target=null;
if(script&&script.dataset&&script.dataset.target){
target=document.querySelector(script.dataset.target);
}else if(script&&script.parentElement){
target=script.parentElement;
}
var autoOpts={};
if(script&&script.dataset){
if(script.dataset.loop==='false')autoOpts.loop=false;
}
if(target)mount(target,SCENE,Object.assign({},OPTIONS,autoOpts));
var api={mount:function(c,opts){return mount(c,SCENE,opts||{});}};
if(typeof window!=='undefined'){
window.AnimatrPlayer=window.AnimatrPlayer||api;
var api={ __v: '${RUNTIME_VERSION}', mount: mount };
window.AnimatrPlayer = api;
var pending = window.__animatrPending;
window.__animatrPending = null;
if (pending) for (var i=0;i<pending.length;i++) { try { pending[i](); } catch(e) { console.error(e); } }
})();
`
const SCENE_BOOT_SOURCE = `(function(){
var SCENE = __SCENE__;
var OPTIONS = __OPTIONS__;
var script = document.currentScript;
var target = null;
if (script && script.dataset && script.dataset.target) target = document.querySelector(script.dataset.target);
else if (script && script.parentElement) target = script.parentElement;
var autoOpts = {};
if (script && script.dataset && script.dataset.loop === 'false') autoOpts.loop = false;
function boot(){
if (!target || !window.AnimatrPlayer) return;
var merged = {};
for (var k in OPTIONS) merged[k] = OPTIONS[k];
for (var k2 in autoOpts) merged[k2] = autoOpts[k2];
window.AnimatrPlayer.mount(target, SCENE, merged);
}
if (window.AnimatrPlayer) boot();
else (window.__animatrPending = window.__animatrPending || []).push(boot);
})();
`
@@ -210,24 +226,54 @@ export interface ExportOptions {
loop?: boolean
}
export function generateExportScript(scene: Scene, options: ExportOptions = {}): string {
const sceneJson = jsonForExport(scene)
const optsJson = JSON.stringify({ loop: options.loop !== false })
export function generateRuntimeScript(): string {
return (
'/* Animatr export — generated ' +
new Date().toISOString() +
' */\n' +
RUNTIME_SOURCE.replace('__SCENE__', sceneJson).replace('__OPTIONS__', optsJson)
'/* Animatr runtime v' + RUNTIME_VERSION + ' — generated ' + new Date().toISOString() + ' */\n' +
ENGINE_SOURCE
)
}
export function downloadExport(scene: Scene, filename = 'animation.js') {
const source = generateExportScript(scene)
triggerDownload(source, filename, 'application/javascript')
export function generateSceneScript(scene: Scene, options: ExportOptions = {}): string {
const sceneJson = jsonForExport(scene)
const optsJson = JSON.stringify({ loop: options.loop !== false })
return (
'/* Animatr scene — generated ' + new Date().toISOString() + '\n' +
' * Requires animatr-runtime.js (v' + RUNTIME_VERSION + ') to be loaded once per page.\n' +
' */\n' +
SCENE_BOOT_SOURCE.replace('__SCENE__', sceneJson).replace('__OPTIONS__', optsJson)
)
}
export function generateBundledScript(scene: Scene, options: ExportOptions = {}): string {
return (
'/* Animatr bundled export — generated ' + new Date().toISOString() + ' */\n' +
ENGINE_SOURCE +
'\n' +
generateSceneScriptBody(scene, options)
)
}
function generateSceneScriptBody(scene: Scene, options: ExportOptions): string {
const sceneJson = jsonForExport(scene)
const optsJson = JSON.stringify({ loop: options.loop !== false })
return SCENE_BOOT_SOURCE.replace('__SCENE__', sceneJson).replace('__OPTIONS__', optsJson)
}
export function downloadRuntime(filename = 'animatr-runtime.js') {
triggerDownload(generateRuntimeScript(), filename, 'application/javascript')
}
export function downloadSceneExport(scene: Scene, filename = 'animation.js') {
triggerDownload(generateSceneScript(scene), filename, 'application/javascript')
}
export function downloadBundledExport(scene: Scene, filename = 'animation-bundled.js') {
triggerDownload(generateBundledScript(scene), filename, 'application/javascript')
}
export function generateExampleHtml(scene: Scene, options: ExportOptions = {}): string {
const script = generateExportScript(scene, options)
const runtime = ENGINE_SOURCE
const sceneBoot = generateSceneScriptBody(scene, options)
const aspect = `${scene.canvas.width} / ${scene.canvas.height}`
return `<!doctype html>
<html lang="de">
@@ -289,18 +335,32 @@ export function generateExampleHtml(scene: Scene, options: ExportOptions = {}):
</head>
<body>
<h1>Animatr Export</h1>
<p>Diese HTML-Datei enthält Runtime + Szene inline — einfach im Browser öffnen.</p>
<p>Runtime einmal laden, dann beliebig viele Szenen auf einer Seite.</p>
<!-- Runtime: einmal pro Seite -->
<script>
${runtime}
</script>
<div class="stage">
<!-- Szene: pro Animation -->
<script>
${script}
${sceneBoot}
</script>
</div>
<div class="usage">
<h2>Einbinden in eine eigene Seite</h2>
<pre>&lt;div style="width: 800px; height: 450px;"&gt;
<pre>&lt;!-- einmal pro Seite --&gt;
&lt;script src="animatr-runtime.js"&gt;&lt;/script&gt;
&lt;!-- je Animation ein Container + Scene-Script --&gt;
&lt;div style="width: 800px; height: 450px;"&gt;
&lt;script src="animation.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;div style="width: 400px; height: 225px;"&gt;
&lt;script src="animation-2.js"&gt;&lt;/script&gt;
&lt;/div&gt;</pre>
</div>
</body>