flow: color, dialog, Evolved
This commit is contained in:
parent
d69f1418e8
commit
15c9851f2a
1
packages/color/.eslintrc.js
Normal file
1
packages/color/.eslintrc.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = require('../../config/.eslintrc');
|
7
packages/color/.gitignore
vendored
Normal file
7
packages/color/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
**/*.js
|
||||
**/*.map
|
||||
!/.*
|
||||
!/postcss.config.js
|
||||
!/webpack.config.js
|
||||
!src/**/*.js
|
||||
!/test/**/*.js
|
1
packages/color/.neutrinorc.js
Normal file
1
packages/color/.neutrinorc.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = require('../../config/.neutrinorc');
|
46
packages/color/package.json
Normal file
46
packages/color/package.json
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "@avocado/color",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "cha0s",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_PATH=./node_modules webpack --mode production",
|
||||
"clean": "rm -rf yarn.lock node_modules $(node -e \"process.stdout.write(require('./package.json').files.filter((file) => {const parts = file.split('/'); return 1 === parts.length || 'test' !== parts[0];}).join(' '));\") && yarn",
|
||||
"forcepub": "npm unpublish --force $(node -e 'const {name, version} = require(`./package.json`); process.stdout.write(`${name}@${version}`)') && npm publish",
|
||||
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
|
||||
"test": "yarn --silent run build --display none && mocha --colors test.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.js.map",
|
||||
"test.js",
|
||||
"test.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"@avocado/behavior": "^2.0.0",
|
||||
"@avocado/traits": "^2.0.0",
|
||||
"@latus/core": "^2.0.0",
|
||||
"debug": "4.3.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb": "^9.4.0",
|
||||
"@neutrinojs/banner": "^9.4.0",
|
||||
"@neutrinojs/copy": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"@neutrinojs/react": "^9.4.0",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"glob": "7.1.6",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"source-map-support": "0.5.19",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3",
|
||||
"webpack-node-externals": "2.5.2"
|
||||
}
|
||||
}
|
6
packages/color/postcss.config.js
Normal file
6
packages/color/postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* eslint-disable global-require */
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer'),
|
||||
],
|
||||
};
|
27
packages/color/src/dialog-functions.js
Normal file
27
packages/color/src/dialog-functions.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import get from 'lodash.get';
|
||||
import set from 'lodash.set';
|
||||
|
||||
import hsv2rgb from './hsv2rgb';
|
||||
|
||||
export default () => ({
|
||||
rainbow: ({
|
||||
active,
|
||||
traits,
|
||||
i,
|
||||
length,
|
||||
}) => {
|
||||
const [red, green, blue] = hsv2rgb([i / length, 1, 1]);
|
||||
set(traits, 'Colorized.state', {red, green, blue});
|
||||
if (active) {
|
||||
const lfo = get(traits, 'Evolving.params.lfo', {});
|
||||
lfo.hue = {
|
||||
frequency: 1,
|
||||
location: ((i % length) / length),
|
||||
magnitude: 1,
|
||||
modulators: ['Sawtooth'],
|
||||
};
|
||||
set(traits, 'Evolving.params.lfo', lfo);
|
||||
}
|
||||
return traits;
|
||||
},
|
||||
});
|
23
packages/color/src/hsv2rgb.js
Normal file
23
packages/color/src/hsv2rgb.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
export default ([h, s, v]) => {
|
||||
let r;
|
||||
let g;
|
||||
let b;
|
||||
const i = Math.floor(h * 6);
|
||||
const f = h * 6 - i;
|
||||
const p = v * (1 - s);
|
||||
const q = v * (1 - f * s);
|
||||
const t = v * (1 - (1 - f) * s);
|
||||
switch (i % 6) {
|
||||
default: [r, g, b] = [v, t, p]; break;
|
||||
case 1: [r, g, b] = [q, v, p]; break;
|
||||
case 2: [r, g, b] = [p, v, t]; break;
|
||||
case 3: [r, g, b] = [p, q, v]; break;
|
||||
case 4: [r, g, b] = [t, p, v]; break;
|
||||
case 5: [r, g, b] = [v, p, q]; break;
|
||||
}
|
||||
return [
|
||||
Math.round(r * 255),
|
||||
Math.round(g * 255),
|
||||
Math.round(b * 255),
|
||||
];
|
||||
};
|
12
packages/color/src/index.js
Normal file
12
packages/color/src/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import {gatherWithLatus} from '@latus/core';
|
||||
|
||||
import dialogFunctions from './dialog-functions';
|
||||
|
||||
export default {
|
||||
hooks: {
|
||||
'@avocado/dialog/functions': dialogFunctions,
|
||||
'@avocado/traits': gatherWithLatus(
|
||||
require.context('./traits', false, /\.js$/),
|
||||
),
|
||||
},
|
||||
};
|
36
packages/color/src/rgb2hsv.js
Normal file
36
packages/color/src/rgb2hsv.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
export default ([r, g, b]) => {
|
||||
const rabs = r / 255;
|
||||
const gabs = g / 255;
|
||||
const babs = b / 255;
|
||||
const v = Math.max(rabs, gabs, babs);
|
||||
const diff = v - Math.min(rabs, gabs, babs);
|
||||
const diffc = (c) => (v - c) / 6 / diff + 1 / 2;
|
||||
let h;
|
||||
let s;
|
||||
if (0 === diff) {
|
||||
h = 0;
|
||||
s = 0;
|
||||
}
|
||||
else {
|
||||
s = diff / v;
|
||||
const rr = diffc(rabs);
|
||||
const gg = diffc(gabs);
|
||||
const bb = diffc(babs);
|
||||
if (rabs === v) {
|
||||
h = bb - gg;
|
||||
}
|
||||
else if (gabs === v) {
|
||||
h = (1 / 3) + rr - bb;
|
||||
}
|
||||
else if (babs === v) {
|
||||
h = (2 / 3) + gg - rr;
|
||||
}
|
||||
if (h < 0) {
|
||||
h += 1;
|
||||
}
|
||||
else if (h > 1) {
|
||||
h -= 1;
|
||||
}
|
||||
}
|
||||
return [h, s, v];
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
import {StateProperty, Trait} from '@avocado/traits';
|
||||
import {compose} from '@latus/core';
|
||||
|
||||
import Color from '../color';
|
||||
import hsv2rgb from '../hsv2rgb';
|
||||
import rgb2hsv from '../rgb2hsv';
|
||||
|
||||
const decorate = compose(
|
||||
StateProperty('red', {
|
||||
|
@ -15,7 +16,7 @@ const decorate = compose(
|
|||
}),
|
||||
);
|
||||
|
||||
export default () => class Colored extends decorate(Trait) {
|
||||
export default () => class Colorized extends decorate(Trait) {
|
||||
|
||||
static children() {
|
||||
return {
|
||||
|
@ -69,7 +70,7 @@ export default () => class Colored extends decorate(Trait) {
|
|||
}
|
||||
|
||||
get hue() {
|
||||
return Color.rgb2hsv(this.red, this.green, this.blue)[0];
|
||||
return rgb2hsv([this.red, this.green, this.blue])[0];
|
||||
}
|
||||
|
||||
set hue(hue) {
|
||||
|
@ -87,7 +88,7 @@ export default () => class Colored extends decorate(Trait) {
|
|||
}
|
||||
|
||||
get saturation() {
|
||||
return Color.rgb2hsv(this.red, this.green, this.blue)[1];
|
||||
return rgb2hsv([this.red, this.green, this.blue])[1];
|
||||
}
|
||||
|
||||
set saturation(saturation) {
|
||||
|
@ -95,7 +96,7 @@ export default () => class Colored extends decorate(Trait) {
|
|||
}
|
||||
|
||||
get value() {
|
||||
return Color.rgb2hsv(this.red, this.green, this.blue)[2];
|
||||
return rgb2hsv([this.red, this.green, this.blue])[2];
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
|
@ -103,19 +104,19 @@ export default () => class Colored extends decorate(Trait) {
|
|||
}
|
||||
|
||||
wrapHsvSet(i, nv) {
|
||||
const hsv = Color.rgb2hsv(this.red, this.green, this.blue);
|
||||
const hsv = rgb2hsv([this.red, this.green, this.blue]);
|
||||
const keys = ['hue', 'saturation', 'value'];
|
||||
if (nv !== hsv[i]) {
|
||||
hsv[i] = nv;
|
||||
[this.red, this.green, this.blue] = Color.hsv2rgb(...hsv);
|
||||
[this.red, this.green, this.blue] = hsv2rgb(hsv);
|
||||
this.entity.emit(`${keys[i]}Changed`);
|
||||
}
|
||||
}
|
||||
|
||||
wrapRgbSet(fn) {
|
||||
const o = Color.rgb2hsv(this.red, this.green, this.blue);
|
||||
const o = rgb2hsv([this.red, this.green, this.blue]);
|
||||
fn();
|
||||
const n = Color.rgb2hsv(this.red, this.green, this.blue);
|
||||
const n = rgb2hsv([this.red, this.green, this.blue]);
|
||||
['hue', 'saturation', 'value'].forEach((key, i) => {
|
||||
if (n[i] !== o[i]) {
|
||||
this.entity.emit(`${key}Changed`);
|
5
packages/color/test/exists.js
Normal file
5
packages/color/test/exists.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
it('exists', () => {
|
||||
expect(true).to.be.true;
|
||||
});
|
3
packages/color/webpack.config.js
Normal file
3
packages/color/webpack.config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();
|
8518
packages/color/yarn.lock
Normal file
8518
packages/color/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
packages/dialog/.eslintrc.js
Normal file
1
packages/dialog/.eslintrc.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = require('../../config/.eslintrc');
|
7
packages/dialog/.gitignore
vendored
Normal file
7
packages/dialog/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
**/*.js
|
||||
**/*.map
|
||||
!/.*
|
||||
!/postcss.config.js
|
||||
!/webpack.config.js
|
||||
!src/**/*.js
|
||||
!/test/**/*.js
|
1
packages/dialog/.neutrinorc.js
Normal file
1
packages/dialog/.neutrinorc.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = require('../../config/.neutrinorc');
|
49
packages/dialog/package.json
Normal file
49
packages/dialog/package.json
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "@avocado/dialog",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "cha0s",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_PATH=./node_modules webpack --mode production",
|
||||
"clean": "rm -rf yarn.lock node_modules $(node -e \"process.stdout.write(require('./package.json').files.filter((file) => {const parts = file.split('/'); return 1 === parts.length || 'test' !== parts[0];}).join(' '));\") && yarn",
|
||||
"forcepub": "npm unpublish --force $(node -e 'const {name, version} = require(`./package.json`); process.stdout.write(`${name}@${version}`)') && npm publish",
|
||||
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
|
||||
"test": "yarn --silent run build --display none && mocha --colors test.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.js.map",
|
||||
"test.js",
|
||||
"test.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"@avocado/traits": "^2.0.0",
|
||||
"@latus/core": "^2.0.0",
|
||||
"debug": "4.3.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"remark-mdx": "2.0.0-next.8",
|
||||
"remark-parse": "8.0.2",
|
||||
"unified": "^9.2.0",
|
||||
"unist-util-visit-parents": "^3.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb": "^9.4.0",
|
||||
"@neutrinojs/banner": "^9.4.0",
|
||||
"@neutrinojs/copy": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"@neutrinojs/react": "^9.4.0",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"glob": "7.1.6",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"source-map-support": "0.5.19",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3",
|
||||
"webpack-node-externals": "2.5.2"
|
||||
}
|
||||
}
|
6
packages/dialog/postcss.config.js
Normal file
6
packages/dialog/postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* eslint-disable global-require */
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer'),
|
||||
],
|
||||
};
|
56
packages/dialog/src/dialog-functions.js
Normal file
56
packages/dialog/src/dialog-functions.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
import get from 'lodash.get';
|
||||
import set from 'lodash.set';
|
||||
|
||||
export default () => ({
|
||||
rate: ({
|
||||
frequency = 0.05,
|
||||
traits,
|
||||
}) => {
|
||||
set(traits, 'DialogText.state.rate', parseInt(frequency, 10));
|
||||
return traits;
|
||||
},
|
||||
shake: ({
|
||||
frequency = 1,
|
||||
magnitude = 3,
|
||||
traits,
|
||||
i,
|
||||
length,
|
||||
}) => {
|
||||
const lfo = get(traits, 'Evolving.params.lfo', {});
|
||||
lfo.x = {
|
||||
frequency,
|
||||
location: ((i % length) / length),
|
||||
magnitude: magnitude / 2,
|
||||
median: 0,
|
||||
modulators: ['Random'],
|
||||
};
|
||||
lfo.y = {
|
||||
frequency,
|
||||
location: ((i % length) / length),
|
||||
magnitude,
|
||||
median: 0,
|
||||
modulators: ['Random'],
|
||||
};
|
||||
set(traits, 'Evolving.params.lfo', lfo);
|
||||
return traits;
|
||||
},
|
||||
wave: ({
|
||||
frequency = 1,
|
||||
magnitude = 3,
|
||||
modulator = 'Sine',
|
||||
traits,
|
||||
i,
|
||||
length,
|
||||
}) => {
|
||||
const lfo = get(traits, 'Evolving.params.lfo', {});
|
||||
lfo.y = {
|
||||
frequency,
|
||||
location: ((i % length) / length),
|
||||
magnitude,
|
||||
median: 0,
|
||||
modulators: [modulator],
|
||||
};
|
||||
set(traits, 'Evolving.params.lfo', lfo);
|
||||
return traits;
|
||||
},
|
||||
});
|
28
packages/dialog/src/index.js
Normal file
28
packages/dialog/src/index.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import {gatherWithLatus} from '@latus/core';
|
||||
|
||||
import dialogFunctions from './dialog-functions';
|
||||
import parse from './parser';
|
||||
import wordize from './wordize';
|
||||
|
||||
export default {
|
||||
hooks: {
|
||||
'@avocado/dialog/functions': dialogFunctions,
|
||||
'@avocado/traits': gatherWithLatus(
|
||||
require.context('./traits', false, /\.js$/),
|
||||
),
|
||||
'@latus/core/starting': (latus) => {
|
||||
const dialogFunctions = latus.invokeReduce('@avocado/dialog/functions');
|
||||
const resolver = (type) => (dialogFunctions[type] ? dialogFunctions[type] : (i) => i);
|
||||
latus.set('%dialogParser', async (text) => {
|
||||
const {Entity} = latus.get('%resources');
|
||||
const letters = await Promise.all(
|
||||
parse(text, resolver).map((letter) => Entity.load({traits: letter})),
|
||||
);
|
||||
return {
|
||||
letters,
|
||||
words: await wordize(letters, latus),
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
109
packages/dialog/src/parser.js
Normal file
109
packages/dialog/src/parser.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
import get from 'lodash.get';
|
||||
import set from 'lodash.set';
|
||||
import mdx from 'remark-mdx';
|
||||
import parse from 'remark-parse';
|
||||
import unified from 'unified';
|
||||
import visit from 'unist-util-visit-parents';
|
||||
|
||||
const letterCount = (node) => {
|
||||
if ('text' === node.type) {
|
||||
return node.value.length;
|
||||
}
|
||||
return node.children.length > 0
|
||||
? node.children.reduce((count, child) => count + letterCount(child), 0)
|
||||
: 0;
|
||||
};
|
||||
|
||||
const decorateWithLetters = (resolver) => (node, ancestors) => {
|
||||
/* eslint-disable no-param-reassign */
|
||||
if ('text' === node.type) {
|
||||
const letters = node.value
|
||||
.replace(/\s/g, '\u00A0')
|
||||
.split('');
|
||||
node.letters = letters.map((letter) => (
|
||||
ancestors.reduce(
|
||||
(traits, ancestor) => ancestor.traits(traits),
|
||||
{
|
||||
DomNode: {
|
||||
params: {
|
||||
style: {
|
||||
display: 'inline-block',
|
||||
position: 'relative',
|
||||
},
|
||||
},
|
||||
},
|
||||
DomText: {
|
||||
params: {
|
||||
centered: false,
|
||||
},
|
||||
},
|
||||
Textual: {
|
||||
state: {
|
||||
text: letter,
|
||||
},
|
||||
},
|
||||
Visible: {
|
||||
state: {
|
||||
opacity: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
));
|
||||
return;
|
||||
}
|
||||
node.traits = (traits) => traits;
|
||||
if ('emphasis' === node.type) {
|
||||
node.traits = (traits) => {
|
||||
const style = get(traits, 'DomNode.params.style', {});
|
||||
style.fontStyle = 'italic';
|
||||
set(traits, 'DomNode.params.style', style);
|
||||
return traits;
|
||||
};
|
||||
}
|
||||
if ('strong' === node.type) {
|
||||
node.traits = (traits) => {
|
||||
const style = get(traits, 'DomNode.params.style', {});
|
||||
style.fontWeight = 'bold';
|
||||
set(traits, 'DomNode.params.style', style);
|
||||
return traits;
|
||||
};
|
||||
}
|
||||
if (
|
||||
'mdxBlockElement' === node.type
|
||||
|| 'mdxSpanElement' === node.type
|
||||
) {
|
||||
const {attributes, name} = node;
|
||||
const length = letterCount(node);
|
||||
let i = 0;
|
||||
node.traits = (traits) => {
|
||||
const args = attributes.reduce((r, {name, value}) => ({
|
||||
...r,
|
||||
[name]: (value?.value ? value.value : value) || true,
|
||||
}), {});
|
||||
return resolver(name)({
|
||||
length,
|
||||
...args,
|
||||
i: i++,
|
||||
traits,
|
||||
});
|
||||
};
|
||||
}
|
||||
/* eslint-enable no-param-reassign */
|
||||
};
|
||||
|
||||
const lettersFor = (node) => {
|
||||
if (node.children) {
|
||||
return node.children.reduce(
|
||||
(r, child) => r.concat(...lettersFor(child)),
|
||||
[],
|
||||
);
|
||||
}
|
||||
return node.letters || [];
|
||||
};
|
||||
|
||||
export default (source, resolver) => {
|
||||
const tree = unified().use(parse).use(mdx).parse(source);
|
||||
visit(tree, decorateWithLetters(resolver));
|
||||
return lettersFor(tree);
|
||||
};
|
16
packages/dialog/src/traits/dialog-text.js
Normal file
16
packages/dialog/src/traits/dialog-text.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import {StateProperty, Trait} from '@avocado/traits';
|
||||
import {compose} from '@latus/core';
|
||||
|
||||
const decorate = compose(
|
||||
StateProperty('rate'),
|
||||
);
|
||||
|
||||
export default () => class DialogText extends decorate(Trait) {
|
||||
|
||||
static defaultState() {
|
||||
return {
|
||||
rate: 0.1,
|
||||
};
|
||||
}
|
||||
|
||||
};
|
90
packages/dialog/src/traits/dialog.js
Normal file
90
packages/dialog/src/traits/dialog.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
import {Trait} from '@avocado/traits';
|
||||
|
||||
export default (latus) => class Dialog extends Trait {
|
||||
|
||||
#dialog;
|
||||
|
||||
#letters = [];
|
||||
|
||||
#nextLetter = 0;
|
||||
|
||||
#thisLetter = 0;
|
||||
|
||||
#words = [];
|
||||
|
||||
static defaultParams() {
|
||||
return {
|
||||
rate: 0.05,
|
||||
};
|
||||
}
|
||||
|
||||
static dependencies() {
|
||||
return [
|
||||
'Textual',
|
||||
'DomNode',
|
||||
];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
hooks() {
|
||||
return {
|
||||
|
||||
visibleAabbs: () => [-64, -64, 64, 64],
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
async load(json) {
|
||||
await super.load(json);
|
||||
if ('client' === process.env.SIDE) {
|
||||
this.entity.node.className = 'dialog';
|
||||
const {text} = this.entity;
|
||||
if (text) {
|
||||
({
|
||||
letters: this.#letters,
|
||||
words: this.#words,
|
||||
} = await latus.get('%dialogParser')(
|
||||
`<rate frequency={${this.params.rate}}>${text}</rate>`,
|
||||
));
|
||||
if (this.#letters.length > 0) {
|
||||
this.showThisLetter();
|
||||
this.#words.forEach((word) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
word.parentNode = this.entity.node;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showThisLetter() {
|
||||
const letter = this.#letters[this.#thisLetter];
|
||||
this.#nextLetter += letter.rate;
|
||||
letter.opacity = 1;
|
||||
}
|
||||
|
||||
skip() {
|
||||
for (let i = 0; i < this.#letters.length; ++i) {
|
||||
this.#letters[i].opacity = 1;
|
||||
}
|
||||
this.#nextLetter = Infinity;
|
||||
}
|
||||
|
||||
tick(elapsed) {
|
||||
if ('client' === process.env.SIDE) {
|
||||
this.#nextLetter -= elapsed;
|
||||
if (this.#nextLetter <= 0) {
|
||||
this.#thisLetter += 1;
|
||||
if (this.#thisLetter >= this.#letters.length) {
|
||||
this.skip();
|
||||
return;
|
||||
}
|
||||
this.showThisLetter();
|
||||
}
|
||||
for (let i = 0; i < this.#words.length; ++i) {
|
||||
this.#words[i].tick(elapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
45
packages/dialog/src/wordize.js
Normal file
45
packages/dialog/src/wordize.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const createWord = async (letters, latus) => {
|
||||
const {Entity} = latus.get('%resources');
|
||||
const word = await Entity.load({
|
||||
traits: {
|
||||
DomNode: {
|
||||
params: {
|
||||
style: {
|
||||
position: 'relative',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
for (let i = 0; i < letters.length; ++i) {
|
||||
/* eslint-disable no-param-reassign */
|
||||
letters[i].parentNode = word.node;
|
||||
letters[i].isBehaving = true;
|
||||
/* eslint-enable no-param-reassign */
|
||||
}
|
||||
const {tick} = word;
|
||||
word.tick = function T(elapsed) {
|
||||
tick.call(this, elapsed);
|
||||
for (let i = 0; i < letters.length; ++i) {
|
||||
letters[i].tick(elapsed);
|
||||
}
|
||||
};
|
||||
return word;
|
||||
};
|
||||
|
||||
export default async (letters, latus) => {
|
||||
const words = [];
|
||||
let word = [];
|
||||
for (let i = 0; i < letters.length; i++) {
|
||||
const {text} = letters[i];
|
||||
word.push(letters[i]);
|
||||
if (text.match(/[^a-zA-Z0-9_]/)) {
|
||||
words.push(createWord(word, latus));
|
||||
word = [];
|
||||
}
|
||||
}
|
||||
if (word.length > 0) {
|
||||
words.push(createWord(word, latus));
|
||||
}
|
||||
return Promise.all(words);
|
||||
};
|
5
packages/dialog/test/exists.js
Normal file
5
packages/dialog/test/exists.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import {expect} from 'chai';
|
||||
|
||||
it('exists', () => {
|
||||
expect(true).to.be.true;
|
||||
});
|
3
packages/dialog/webpack.config.js
Normal file
3
packages/dialog/webpack.config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();
|
8809
packages/dialog/yarn.lock
Normal file
8809
packages/dialog/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,7 @@ export default () => class DomNode extends decorate(Trait) {
|
|||
|
||||
static dependencies() {
|
||||
return [
|
||||
'Positioned',
|
||||
'Visible',
|
||||
];
|
||||
}
|
||||
|
|
|
@ -6,13 +6,14 @@ export default () => class DomText extends Trait {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
this.#text = window.document.createElement('span');
|
||||
if ('client' === process.env.SIDE) {
|
||||
this.#text = window.document.createElement('span');
|
||||
}
|
||||
}
|
||||
|
||||
static defaultParams() {
|
||||
return {
|
||||
centered: true,
|
||||
textStyle: {},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -47,23 +48,28 @@ export default () => class DomText extends Trait {
|
|||
|
||||
async load(json) {
|
||||
await super.load(json);
|
||||
if (!this.#text) {
|
||||
return;
|
||||
}
|
||||
const {text} = this.entity;
|
||||
this.#text.innerText = text;
|
||||
Object.entries(this.params.textStyle).forEach(([key, value]) => {
|
||||
this.#text.style[key] = value;
|
||||
});
|
||||
this.#text.style.position = 'relative';
|
||||
if (this.params.centered) {
|
||||
const {fontSize: fontSizeInPx = '16px'} = this.params.textStyle;
|
||||
const fontSize = parseInt(fontSizeInPx, 10);
|
||||
this.#text.style.left = `-${(fontSize / 2) * text.length}px`;
|
||||
this.#text.style.top = `-${(fontSize / 2)}px`;
|
||||
const {fontSize} = this.params;
|
||||
if (fontSize) {
|
||||
this.#text.style.fontSize = `${fontSize}px`;
|
||||
if (this.params.centered) {
|
||||
this.#text.style.left = `-${(fontSize / 2) * text.length}px`;
|
||||
this.#text.style.top = `-${(fontSize / 2)}px`;
|
||||
}
|
||||
}
|
||||
this.entity.node.appendChild(this.#text);
|
||||
}
|
||||
|
||||
onColorChanged() {
|
||||
if (this.entity.is('Colored')) {
|
||||
if (!this.#text) {
|
||||
return;
|
||||
}
|
||||
if (this.entity.is('Colorized')) {
|
||||
const {red, green, blue} = this.entity;
|
||||
this.#text.style.color = `rgb(${red}, ${green}, ${blue})`;
|
||||
}
|
||||
|
|
25
packages/timing/src/traits/evolving.js
Normal file
25
packages/timing/src/traits/evolving.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import {Trait} from '@avocado/traits';
|
||||
|
||||
export default () => class Evolving extends Trait {
|
||||
|
||||
#evolving;
|
||||
|
||||
static defaultParams() {
|
||||
return {
|
||||
lfo: {},
|
||||
};
|
||||
}
|
||||
|
||||
async load(json) {
|
||||
await super.load(json);
|
||||
if (0 === Object.keys(this.params.lfo).length) {
|
||||
return;
|
||||
}
|
||||
this.#evolving = this.entity.lfo(this.params.lfo);
|
||||
}
|
||||
|
||||
tick(elapsed) {
|
||||
this.#evolving.tick(elapsed);
|
||||
}
|
||||
|
||||
};
|
Loading…
Reference in New Issue
Block a user