Przeglądaj źródła

Start implementing a drag-and-drop based UI

master
Fen Dweller 4 lat temu
rodzic
commit
1b9e15f632
6 zmienionych plików z 204 dodań i 77 usunięć
  1. BIN
      public/favicon.ico
  2. +54
    -71
      src/Dissolve.vue
  3. +41
    -0
      src/components/Draggable.vue
  4. +58
    -0
      src/components/Menu.vue
  5. +35
    -2
      src/components/SoundscapeComp.vue
  6. +16
    -4
      src/components/nodes/SourceNode.vue

BIN
public/favicon.ico Wyświetl plik

Przed Po

+ 54
- 71
src/Dissolve.vue Wyświetl plik

@@ -1,40 +1,26 @@
<template>
<h1>Dissolve</h1>
<div>This is a mega-early-alpha vore audio generator.</div>
<div>
Follow <a href="https://twitter.com/causticcrux">@causticcrux</a> for more.
<div id="app-area">
<Menu />

<div id="soundscapes">
<SoundscapeComp
v-for="(soundscape, index) in soundscapes"
:key="index"
:soundscape="soundscape"
/>
</div>
</div>
<div>
Many sounds by <a href="https://www.furaffinity.net/user/jeschke">Jit</a>!
</div>
<button v-on:click="start" class="start-button" v-if="!started">
Start
</button>
<button v-on:click="addSoundscape" class="start-button" v-if="started">
Add Soundscape
</button>
<SoundscapeComp
v-for="(soundscape, index) in soundscapes"
:key="index"
:soundscape="soundscape"
/>

<button v-on:click="clear">Delete all cached sound (if it gets stuck)</button>
</template>

<script lang="ts">
import { Options, Vue } from "vue-class-component";
import { clearCache, setup, Soundscape } from "./audio";
import SoundscapeComp from "./components/SoundscapeComp.vue";
import { Filter } from "./filters/Filter";
import { HighpassFilter } from "./filters/HighpassFilter";
import { LowpassFilter } from "./filters/LowpassFilter";
import { StereoWidthFilter } from "./filters/StereoWidthFilter";
import { LoopingSource } from "./sources/LoopingSource";
import * as Sources from "./sources/PremadeSources";
import Menu from "./components/Menu.vue";
@Options({
components: {
SoundscapeComp,
Menu,
},
})
export default class Dissolve extends Vue {
@@ -42,59 +28,19 @@ export default class Dissolve extends Vue {
started = false;
soundscapes: Array<Soundscape> = [];

addSoundscape(): void {
const scape: Soundscape = new Soundscape();
scape.addSource(Sources.makeGlorps());
scape.addSource(Sources.makeGurgles());
scape.addSource(Sources.makeHeartbeat());
scape.addSource(Sources.makeRumble());
scape.addSource(Sources.makeSquishing());
scape.addSource(Sources.makeBreathing());
scape.addSource(Sources.makeBurps());

scape.addFilter(new LowpassFilter());
scape.addFilter(new HighpassFilter());
scape.addFilter(new StereoWidthFilter());

addSoundscape(scape: Soundscape): void {
scape.output.connect(this.context.destination);

this.soundscapes.push(scape);
}
start(): void {
this.started = true;

const internal: Soundscape = new Soundscape();
internal.addSource(Sources.makeGlorps());
internal.addSource(Sources.makeGurgles());
internal.addSource(Sources.makeHeartbeat());
internal.addSource(Sources.makeRumble());
internal.addSource(Sources.makeSquishing());

internal.output.connect(this.context.destination);

this.soundscapes.push(internal);

const external: Soundscape = new Soundscape();

const breathing: LoopingSource = Sources.makeBreathing();
breathing.volume = 0.3;
external.addSource(breathing);
external.addSource(Sources.makeBurps());

const lowpass: Filter = new LowpassFilter();
lowpass.active = true;
external.addFilter(lowpass);
const highpass: Filter = new HighpassFilter();
highpass.active = false;
external.addFilter(highpass);

external.output.connect(this.context.destination);

this.soundscapes.push(external);
}

mounted(): void {
this.context = setup();

this.addSoundscape(new Soundscape());
}

clear(): void {
@@ -104,17 +50,54 @@ export default class Dissolve extends Vue {
</script>

<style>
@import url("https://fonts.googleapis.com/css2?family=Coda&display=swap");

html {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
background: #111;
width: 100%;
height: 100%;
}

#dissolve-title {
margin-top: 0;
}

#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
font-family: "Coda", cursive;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #ddd;
background: #111;
margin-top: 60px;
height: 100%;
width: 100%;
box-sizing: border-box;
}

#app-area {
display: flex;
flex-direction: row;
height: 100%;
width: 100%;
}

#menu {
flex: 1 0 100px;
}

#soundscapes {
flex: 5 0 50vw;
display: grid;
grid-template-columns: 400px 400px 400px;
grid-auto-rows: auto-fit;
}

.start-button {


+ 41
- 0
src/components/Draggable.vue Wyświetl plik

@@ -0,0 +1,41 @@
<template>
<div class="draggable" draggable="true" v-on:dragstart="dragstart">
<div class="label">{{ label }}</div>
</div>
</template>

<script lang="ts">
import { Options, Vue } from "vue-class-component";

@Options({
props: {
label: String,
},
})
export default class Draggable extends Vue {
label!: string;

dragstart(event: DragEvent): void {
console.log(event?.dataTransfer);
event?.dataTransfer?.setData("text/plain", this.label);
}
}
</script>

<style scoped>
.draggable {
width: 100%;
height: auto;
background: darkgray;
box-shadow: 3px 3px 3px black;
border-radius: 4px;
cursor: grab;
}

.label {
margin: auto;
height: 100%;
font-size: 24pt;
text-align: center;
}
</style>

+ 58
- 0
src/components/Menu.vue Wyświetl plik

@@ -0,0 +1,58 @@
<template>
<div id="menu">
<div class="list-label">Sources</div>
<div class="list">
<draggable
v-for="(source, index) in sourceTypes"
:key="index"
:label="source"
/>
</div>
</div>
</template>

<script lang="ts">
import { Options, Vue } from "vue-class-component";
import Draggable from "@/components/Draggable.vue";

@Options({
components: {
Draggable,
},
})
export default class Menu extends Vue {
sourceTypes = [
"Rumble",
"Glorps",
"Heartbeat",
"Breathing",
"Squishing",
"Burps",
"Gurgles",
];

foo = 3;
}
</script>

<style scoped>
#menu {
background: gray;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
}

.list-label {
font-size: 36pt;
}

.list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-auto-rows: minmax(max-content, 1fr);
background: #777;
}
</style>

+ 35
- 2
src/components/SoundscapeComp.vue Wyświetl plik

@@ -6,6 +6,11 @@
:source="source"
>
</source-node>
<source-node
v-on:drop="drop"
v-on:dragover="drag"
:dummy="true"
></source-node>
<filter-node
v-for="(filter, index) in soundscape.filters"
:key="index"
@@ -21,6 +26,8 @@ import { Soundscape } from "@/audio";
import { Options, Vue } from "vue-class-component";
import SourceNode from "./nodes/SourceNode.vue";
import FilterNode from "./nodes/FilterNode.vue";
import * as Sources from "@/sources/PremadeSources";
import { Source } from "@/sources/Source";

@Options({
props: {
@@ -36,6 +43,31 @@ export default class SoundscapeComp extends Vue {
started = false;
context!: AudioContext;

makers: Record<string, () => Source> = {
Gurgles: Sources.makeGurgles,
Burps: Sources.makeBurps,
Glorps: Sources.makeGlorps,
Squishing: Sources.makeSquishing,
Heartbeat: Sources.makeHeartbeat,
Breathing: Sources.makeBreathing,
Rumble: Sources.makeRumble,
};

drag(ev: DragEvent): void {
ev.preventDefault();
}

drop(event: DragEvent): void {
event.preventDefault();

if (event.dataTransfer) {
const label = event.dataTransfer.getData("text/plain");

console.log(this.makers[label])
this.soundscape.addSource(this.makers[label]());
}
}

mounted(): void {
this.soundscape.start();
}
@@ -44,12 +76,13 @@ export default class SoundscapeComp extends Vue {

<style scoped>
.soundscape {
width: auto;
height: max-content;
margin: auto;
padding: 20px;
margin: 20px;
height: 100%;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
grid-template-columns: repeat(auto-fit, minmax(1fr, 400px));
grid-auto-rows: auto-fit;
grid-gap: 20px;
background: #222;


+ 16
- 4
src/components/nodes/SourceNode.vue Wyświetl plik

@@ -1,8 +1,15 @@
<template>
<div :class="source.active ? '' : 'inactive'" class="source-node">
<Toggle class="active-toggle" v-model="source.active" />
<div class="node-name">{{ source.name }}</div>
<node-props :node="source"></node-props>
<div>
<div
v-if="!dummy"
:class="source.active ? '' : 'inactive'"
class="source-node"
>
<Toggle class="active-toggle" v-model="source.active" />
<div class="node-name">{{ source.name }}</div>
<node-props :node="source"></node-props>
</div>
<div v-if="dummy" class="source-node dummy">Drop here!</div>
</div>
</template>

@@ -15,6 +22,7 @@ import Toggle from "@vueform/toggle";
@Options({
props: {
source: Source,
dummy: false,
},
components: {
NodeProps,
@@ -57,4 +65,8 @@ export default class SourceNode extends Vue {
top: 10px;
left: 10px;
}

.dummy {
min-height: 200px;
}
</style>

Ładowanie…
Anuluj
Zapisz