কেস স্টাডি - বিল্ডিং টেকনিটোন ডট কম

শন মিডলডিচ
Sean Middleditch
টেকনিটোন - একটি ওয়েব অডিও অভিজ্ঞতা।

Technitone.com হল WebGL, Canvas, Web Sockets, CSS3, Javascript, Flash, এবং Chrome-এ নতুন ওয়েব অডিও API- এর ফিউশন।

এই নিবন্ধটি উৎপাদনের প্রতিটি দিককে ভিত্তি করে স্পর্শ করবে: পরিকল্পনা, সার্ভার, শব্দ, ভিজ্যুয়াল, এবং কিছু কর্মপ্রবাহ যা আমরা ইন্টারেক্টিভের জন্য ডিজাইন করতে ব্যবহার করি। বেশিরভাগ বিভাগে কোড স্নিপেট, একটি ডেমো এবং একটি ডাউনলোড থাকে। নিবন্ধের শেষে, একটি ডাউনলোড লিঙ্ক রয়েছে যেখানে আপনি সেগুলিকে একটি জিপ ফাইল হিসাবে ধরতে পারেন।

gskinner.com প্রযোজনা দল।

গিগ

আমরা কোনোভাবেই gskinner.com-এ অডিও ইঞ্জিনিয়ার নই — কিন্তু আমাদেরকে একটি চ্যালেঞ্জ দিয়ে প্রলুব্ধ করি এবং আমরা একটি পরিকল্পনা বের করব:

  • ব্যবহারকারীরা আন্দ্রের টোনম্যাট্রিক্স দ্বারা "অনুপ্রাণিত" একটি গ্রিডে টোন প্লট করে৷
  • টোনগুলি নমুনাযুক্ত যন্ত্র, ড্রাম কিট বা এমনকি ব্যবহারকারীদের নিজস্ব রেকর্ডিংয়ের সাথে সংযুক্ত থাকে
  • একাধিক সংযুক্ত ব্যবহারকারী একই গ্রিডে একই সাথে খেলতে পারেন
  • …অথবা একক মোডে যান নিজেরাই অন্বেষণ করতে
  • আমন্ত্রণমূলক সেশনগুলি ব্যবহারকারীদের একটি ব্যান্ড সংগঠিত করতে এবং একটি অবিলম্বে জ্যাম করার অনুমতি দেয়৷

আমরা ব্যবহারকারীদের একটি টুল প্যানেলের মাধ্যমে ওয়েব অডিও API অন্বেষণ করার একটি সুযোগ অফার করি যা তাদের টোনে অডিও ফিল্টার এবং প্রভাব প্রয়োগ করে।

gskinner.com দ্বারা টেকনিটোন

আমরাও:

  • ব্যবহারকারীদের রচনা এবং প্রভাব ডেটা হিসাবে সঞ্চয় করুন এবং এটি ক্লায়েন্ট জুড়ে সিঙ্ক করুন
  • কিছু রঙের বিকল্প প্রদান করুন যাতে তারা সুন্দর চেহারার গান আঁকতে পারে
  • একটি গ্যালারি অফার করুন যাতে লোকেরা অন্য লোকেদের কাজ শুনতে, ভালোবাসতে বা এমনকি সম্পাদনা করতে পারে৷

আমরা পরিচিত গ্রিড রূপকের সাথে আটকেছি, এটিকে 3D স্পেসে ভাসিয়েছি, কিছু আলোক, টেক্সচার এবং কণা প্রভাব যুক্ত করেছি, এটি একটি নমনীয় (বা ফুলস্ক্রিন) CSS এবং JS-চালিত ইন্টারফেসে রেখেছি।

রাস্তা যাত্রা

উপকরণ, প্রভাব, এবং গ্রিড ডেটা ক্লায়েন্টের উপর একত্রিত এবং সিরিয়ালাইজ করা হয়, তারপর একাধিক ব্যবহারকারীর জন্য সমাধান করতে আমাদের কাস্টম Node.js ব্যাকএন্ডে পাঠানো হয় à la Socket.io । মাল্টি-ইউজার প্লেব্যাকের সময় UI, নমুনা এবং প্রভাবগুলি রেন্ডার করার দায়িত্বে আপেক্ষিক CSS, WebGL এবং WebAudio স্তরগুলিতে ছড়িয়ে দেওয়ার আগে এই ডেটা প্রতিটি খেলোয়াড়ের অবদান সহ ক্লায়েন্টের কাছে ফেরত পাঠানো হয়।

সকেটের সাথে রিয়েল-টাইম যোগাযোগ ক্লায়েন্টে জাভাস্ক্রিপ্ট এবং সার্ভারে জাভাস্ক্রিপ্ট ফিড করে।

টেকনিটোন সার্ভার ডায়াগ্রাম

আমরা সার্ভারের প্রতিটি দিকের জন্য নোড ব্যবহার করি। এটি একটি স্ট্যাটিক ওয়েব সার্ভার এবং আমাদের সকেট সার্ভার সব এক সাথে। এক্সপ্রেস হল যা আমরা ব্যবহার করে শেষ করেছি, এটি সম্পূর্ণরূপে নোডে নির্মিত একটি সম্পূর্ণ ওয়েব সার্ভার। এটি সুপার স্কেলযোগ্য, অত্যন্ত কাস্টমাইজযোগ্য এবং আপনার জন্য নিম্ন-স্তরের সার্ভারের দিকগুলি পরিচালনা করে (যেমন অ্যাপাচি বা উইন্ডোজ সার্ভার করবে)। তারপরে আপনাকে, বিকাশকারী হিসাবে, শুধুমাত্র আপনার অ্যাপ্লিকেশন তৈরিতে ফোকাস করতে হবে।

মাল্টি-ইউজার ডেমো (ঠিক আছে, এটি সত্যিই একটি স্ক্রিনশট)

এই ডেমোটি একটি নোড সার্ভার থেকে চালানো প্রয়োজন, এবং যেহেতু এই নিবন্ধটি একটি নয়, আপনি Node.js ইনস্টল করার পরে, আপনার ওয়েব সার্ভার কনফিগার করার পরে এবং স্থানীয়ভাবে চালানোর পরে ডেমোটি কেমন দেখায় তার একটি স্ক্রিনশট আমরা অন্তর্ভুক্ত করেছি৷ . যখনই একজন নতুন ব্যবহারকারী আপনার ডেমো ইনস্টলেশন পরিদর্শন করবে, একটি নতুন গ্রিড যুক্ত হবে এবং প্রত্যেকের কাজ একে অপরের কাছে দৃশ্যমান হবে।

Node.js ডেমোর স্ক্রিনশট

নোড সহজ। Socket.io এবং কাস্টম POST অনুরোধগুলির একটি কম্বো ব্যবহার করে, আমাদের সিঙ্ক্রোনাইজেশনের জন্য জটিল রুটিন তৈরি করতে হবে না। Socket.io স্বচ্ছভাবে এটি পরিচালনা করে; JSON চারপাশে পাস হয়.

কত সহজ? এটা দেখ.

জাভাস্ক্রিপ্টের 3 লাইনের সাথে আমাদের একটি ওয়েব সার্ভার আছে এবং এক্সপ্রেসের সাথে চলছে।

//Tell  our Javascript file we want to use express.
var express = require('express');

//Create our web-server
var server = express.createServer();

//Tell express where to look for our static files.
server.use(express.static(__dirname + '/static/'));

রিয়েল-টাইম যোগাযোগের জন্য socket.io টাই করার জন্য আরও কয়েকটি।

var io = require('socket.io').listen(server);
//Start listening for socket commands
io.sockets.on('connection', function (socket) {
    //User is connected, start listening for commands.
    socket.on('someEventFromClient', handleEvent);

});

এখন আমরা শুধু HTML পৃষ্ঠা থেকে ইনকামিং সংযোগের জন্য শুনতে শুরু করি।

<!-- Socket-io will serve it-self when requested from this url. -->
<script type="text/javascript" src="/socket.io/socket.io.js"></script>

 <!-- Create our socket and connect to the server -->
 var sock = io.connect('http://localhost:8888');
 sock.on("connect", handleConnect);

 function handleConnect() {
    //Send a event to the server.
    sock.emit('someEventFromClient', 'someData');
 }
 ```

## Sound check

A big unknown was the effort entailed with using the Web Audio API. Our initial findings confirmed that [Digital Signal Processing](http://en.wikipedia.org/wiki/Digital_Signal_Processing) (DSP) is very complex, and we were likely in way over our heads. Second realization: [Chris Rogers](http://chromium.googlecode.com/svn/trunk/samples/audio/index.html) has already done the heavy lifting in the API.
Technitone isn't using any really complex math or audioholicism; this functionality is easily accessible to interested developers. We really just needed to brush up on some terminology and [read the docs](https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html). Our advice? Don't skim them. Read them. Start at the top and end at the bottom. They are peppered with diagrams and photos, and it's really cool stuff.

If this is the first you've heard of the Web Audio API, or don't know what it can do, hit up Chris Rogers' [demos](http://chromium.googlecode.com/svn/trunk/samples/audio/index.html). Looking for inspiration? You'll definitely find it there.

### Web Audio API Demo

Load in a sample (sound file)…

```js
/**
 * The XMLHttpRequest allows you to get the load
 * progress of your file download and has a responseType
 * of "arraybuffer" that the Web Audio API uses to
 * create its own AudioBufferNode.
 * Note: the 'true' parameter of request.open makes the
 * request asynchronous - this is required!
 */
var request = new XMLHttpRequest();
request.open("GET", "mySample.mp3", true);
request.responseType = "arraybuffer";
request.onprogress = onRequestProgress; // Progress callback.
request.onload = onRequestLoad; // Complete callback.
request.onerror = onRequestError; // Error callback.
request.onabort = onRequestError; // Abort callback.
request.send();

// Use this context to create nodes, route everything together, etc.
var context = new webkitAudioContext();

// Feed this AudioBuffer into your AudioBufferSourceNode:
var audioBuffer = null;

function onRequestProgress (event) {
    var progress = event.loaded / event.total;
}

function onRequestLoad (event) {
    // The 'true' parameter specifies if you want to mix the sample to mono.
    audioBuffer = context.createBuffer(request.response, true);
}

function onRequestError (event) {
    // An error occurred when trying to load the sound file.
}

…মডুলার রাউটিং সেট আপ করুন...

/**
 * Generally you'll want to set up your routing like this:
 * AudioBufferSourceNode > [effect nodes] > CompressorNode > AudioContext.destination
 * Note: nodes are designed to be able to connect to multiple nodes.
 */

// The DynamicsCompressorNode makes the loud parts
// of the sound quieter and quiet parts louder.
var compressorNode = context.createDynamicsCompressor();
compressorNode.connect(context.destination);

// [other effect nodes]

// Create and route the AudioBufferSourceNode when you want to play the sample.

…একটি রানটাইম প্রভাব প্রয়োগ করুন (একটি আবেগ প্রতিক্রিয়া ব্যবহার করে কনভল্যুশন)...

/**
 * Your routing now looks like this:
 * AudioBufferSourceNode > ConvolverNode > CompressorNode > AudioContext.destination
 */

var convolverNode = context.createConvolver();
convolverNode.connect(compressorNode);
convolverNode.buffer = impulseResponseAudioBuffer;

…অন্য রানটাইম প্রভাব প্রয়োগ করুন (বিলম্ব)...

/**
 * The delay effect needs some special routing.
 * Unlike most effects, this one takes the sound data out
 * of the flow, reinserts it after a specified time (while
 * looping it back into itself for another iteration).
 * You should add an AudioGainNode to quieten the
 * delayed sound...just so things don't get crazy :)
 *
 * Your routing now looks like this:
 * AudioBufferSourceNode -> ConvolverNode > CompressorNode > AudioContext.destination
 *                       |  ^
 *                       |  |___________________________
 *                       |  v                          |
 *                       -> DelayNode > AudioGainNode _|
 */

var delayGainNode = context.createGainNode();
delayGainNode.gain.value = 0.7; // Quieten the feedback a bit.
delayGainNode.connect(convolverNode);

var delayNode = context.createDelayNode();
delayNode.delayTime = 0.5; // Re-sound every 0.5 seconds.
delayNode.connect(delayGainNode);

delayGainNode.connect(delayNode); // make the loop

…এবং তারপর এটি শ্রবণযোগ্য করা.

/**
 * Once your routing is set up properly, playing a sound
 * is easy-shmeezy. All you need to do is create an
 * AudioSourceBufferNode, route it, and tell it what time
 * (in seconds relative to the currentTime attribute of
 * the AudioContext) it needs to play the sound.
 *
 * 0 == now!
 * 1 == one second from now.
 * etc...
 */

var sourceNode = context.createBufferSource();
sourceNode.connect(convolverNode);
sourceNode.connect(delayNode);
sourceNode.buffer = audioBuffer;
sourceNode.noteOn(0); // play now!

টেকনিটোনে প্লেব্যাক করার জন্য আমাদের দৃষ্টিভঙ্গি হল সময়সূচী সম্পর্কে। প্রতি বীট শব্দগুলি প্রক্রিয়া করার জন্য আমাদের টেম্পোর সমান একটি টাইমার ব্যবধান সেট করার পরিবর্তে, আমরা একটি ছোট ব্যবধান সেট আপ করি যা একটি সারিতে শব্দগুলি পরিচালনা এবং সময়সূচী করে। এটি এপিআইকে অডিও ডেটা এবং প্রক্রিয়াকরণের ফিল্টার এবং প্রভাবগুলি সমাধান করার জন্য আপ-ফ্রন্ট শ্রম সঞ্চালনের অনুমতি দেয় আমরা সিপিইউকে বাস্তবে শ্রবণযোগ্য করে তোলার কাজ করার আগে। যখন সেই বীটটি শেষ পর্যন্ত আসে, তখন স্পীকারদের কাছে নেট ফলাফল উপস্থাপন করার জন্য প্রয়োজনীয় সমস্ত তথ্য ইতিমধ্যেই রয়েছে৷

সামগ্রিকভাবে, সবকিছু অপ্টিমাইজ করা প্রয়োজন. যখন আমরা আমাদের সিপিইউগুলিকে খুব শক্তভাবে ঠেলে দিয়েছিলাম, সময়সূচী মেনে চলার জন্য প্রক্রিয়াগুলি এড়িয়ে যায় (পপ, ক্লিক, স্ক্র্যাচ); আপনি যদি ক্রোমের অন্য ট্যাবে ঝাঁপ দেন তবে আমরা সমস্ত পাগলামি বন্ধ করার জন্য গুরুতর প্রচেষ্টা করি৷

আলোকপ্রদর্শনী

সামনে এবং কেন্দ্র হল আমাদের গ্রিড এবং কণা টানেল। এটি টেকনিটোনের ওয়েবজিএল স্তর।

প্রসেসরের সাথে একত্রে কাজ করার জন্য GPU-কে দায়িত্ব দিয়ে ওয়েবজিএল ওয়েবে ভিজ্যুয়াল রেন্ডার করার অন্যান্য পদ্ধতির তুলনায় যথেষ্ট উন্নত কর্মক্ষমতা প্রদান করে। যে কর্মক্ষমতা লাভ একটি অনেক বেশি খাড়া শেখার বক্ররেখার সাথে উল্লেখযোগ্যভাবে আরও জড়িত বিকাশের ব্যয়ের সাথে আসে। এতে বলা হয়েছে, আপনি যদি ওয়েবে ইন্টারেক্টিভ সম্পর্কে সত্যিই আগ্রহী হন এবং যতটা সম্ভব কম কর্মক্ষমতা নিয়ন্ত্রণ করতে চান, WebGL ফ্ল্যাশের সাথে তুলনীয় একটি সমাধান অফার করে।

ওয়েবজিএল ডেমো

WebGL বিষয়বস্তু একটি ক্যানভাসে রেন্ডার করা হয় (আক্ষরিক অর্থে, HTML5 ক্যানভাস) এবং এই মূল বিল্ডিং ব্লকগুলি নিয়ে গঠিত:

  • বস্তুর শীর্ষবিন্দু (জ্যামিতি)
  • অবস্থান ম্যাট্রিক্স (3D স্থানাঙ্ক)
    • শেডার্স (জ্যামিতি চেহারার একটি বিবরণ, সরাসরি GPU এর সাথে লিঙ্ক করা)
    • প্রসঙ্গ (জিপিইউ রেফারেন্স করে এমন উপাদানগুলির "শর্টকাট")
    • বাফার (জিপিইউতে প্রসঙ্গ ডেটা পাঠানোর জন্য পাইপলাইন)
    • প্রধান কোড (কাঙ্ক্ষিত ইন্টারেক্টিভের জন্য নির্দিষ্ট ব্যবসায়িক যুক্তি)
    • "ড্র" পদ্ধতি (শেডার সক্রিয় করে এবং ক্যানভাসে পিক্সেল আঁকে)

স্ক্রীনে WebGL বিষয়বস্তু রেন্ডার করার প্রাথমিক প্রক্রিয়াটি এরকম দেখাচ্ছে:

  1. পরিপ্রেক্ষিত ম্যাট্রিক্স সেট করুন (ক্যামেরার জন্য সেটিংস সামঞ্জস্য করে যা 3D স্পেসে পিয়ার করে, ছবির সমতলকে সংজ্ঞায়িত করে)।
  2. অবস্থান ম্যাট্রিক্স সেট করুন (3D স্থানাঙ্কে একটি উত্স ঘোষণা করুন যে অবস্থানগুলি আপেক্ষিকভাবে পরিমাপ করা হয়)।
  3. শেডারের মাধ্যমে প্রেক্ষাপটে যাওয়ার জন্য ডেটা (উল্লম্ব অবস্থান, রঙ, টেক্সচার...) দিয়ে বাফারগুলি পূরণ করুন।
  4. শেডারগুলির সাথে বাফারগুলি থেকে ডেটা বের করুন এবং সংগঠিত করুন এবং এটি GPU-তে পাস করুন৷
  5. শেডার সক্রিয় করতে, ডেটা দিয়ে চালাতে এবং ক্যানভাস আপডেট করতে প্রসঙ্গ বলতে ড্র পদ্ধতিতে কল করুন।

এটি কর্মে এই মত দেখায়:

পরিপ্রেক্ষিত ম্যাট্রিক্স সেট করুন...

// Aspect ratio (usually based off the viewport,
// as it can differ from the canvas dimensions).
var aspectRatio = canvas.width / canvas.height;

// Set up the camera view with this matrix.
mat4.perspective(45, aspectRatio, 0.1, 1000.0, pMatrix);

// Adds the camera to the shader. [context = canvas.context]
// This will give it a point to start rendering from.
context.uniformMatrix4fv(shader.pMatrixUniform, 0, pMatrix);

…পজিশন ম্যাট্রিক্স সেট করুন...

// This resets the mvMatrix. This will create the origin in world space.
mat4.identity(mvMatrix);

// The mvMatrix will be moved 20 units away from the camera (z-axis).
mat4.translate(mvMatrix, [0,0,-20]);

// Sets the mvMatrix in the shader like we did with the camera matrix.
context.uniformMatrix4fv(shader.mvMatrixUniform, 0, mvMatrix);

…কিছু জ্যামিতি এবং চেহারা সংজ্ঞায়িত করুন...

// Creates a square with a gradient going from top to bottom.
// The first 3 values are the XYZ position; the last 4 are RGBA.
this.vertices = new Float32Array(28);
this.vertices.set([-2,-2, 0,    0.0, 0.0, 0.7, 1.0,
                   -2, 2, 0,    0.0, 0.4, 0.9, 1.0,
                    2, 2, 0,    0.0, 0.4, 0.9, 1.0,
                    2,-2, 0,    0.0, 0.0, 0.7, 1.0
                  ]);

// Set the order of which the vertices are drawn. Repeating values allows you
// to draw to the same vertex again, saving buffer space and connecting shapes.
this.indices = new Uint16Array(6);
this.indices.set([0,1,2, 0,2,3]);

… ডেটা দিয়ে বাফারগুলি পূরণ করুন এবং এটিকে প্রসঙ্গে প্রেরণ করুন...

// Create a new storage space for the buffer and assign the data in.
context.bindBuffer(context.ARRAY_BUFFER, context.createBuffer());
context.bufferData(context.ARRAY_BUFFER, this.vertices, context.STATIC_DRAW);

// Separate the buffer data into its respective attributes per vertex.
context.vertexAttribPointer(shader.vertexPositionAttribute,3,context.FLOAT,0,28,0);
context.vertexAttribPointer(shader.vertexColorAttribute,4,context.FLOAT,0,28,12);

// Create element array buffer for the index order.
context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, context.createBuffer());
context.bufferData(context.ELEMENT_ARRAY_BUFFER, this.indices, context.STATIC_DRAW);

…এবং ড্র পদ্ধতিতে কল করুন

// Draw the triangles based off the order: [0,1,2, 0,2,3].
// Draws two triangles with two shared points (a square).
context.drawElements(context.TRIANGLES, 6, context.UNSIGNED_SHORT, 0);

প্রতিটি ফ্রেম, ক্যানভাস পরিষ্কার করতে মনে রাখবেন যদি আপনি আলফা-ভিত্তিক ভিজ্যুয়ালগুলি একে অপরের উপর স্ট্যাক আপ করতে না চান।

ঘটনাস্থল

গ্রিড এবং কণা টানেল ছাড়াও, অন্য প্রতিটি UI উপাদান জাভাস্ক্রিপ্টে HTML/CSS এবং ইন্টারেক্টিভ লজিকে তৈরি করা হয়েছিল।

শুরু থেকেই, আমরা সিদ্ধান্ত নিয়েছি যে ব্যবহারকারীদের যত তাড়াতাড়ি সম্ভব গ্রিডের সাথে ইন্টারঅ্যাক্ট করা উচিত। কোন স্প্ল্যাশ স্ক্রীন, কোন নির্দেশনা, কোন টিউটোরিয়াল নেই, শুধু 'যাও'। যদি ইন্টারফেসটি লোড করা হয় - তাদের ধীর করার কিছু থাকা উচিত নয়।

এটির জন্য আমাদেরকে তাদের মিথস্ক্রিয়াগুলির মাধ্যমে প্রথমবারের ব্যবহারকারীকে কীভাবে গাইড করা যায় তা সাবধানতার সাথে দেখতে হবে। আমরা সূক্ষ্ম সংকেত অন্তর্ভুক্ত করেছি, যেমন WebGL স্পেসের মধ্যে ব্যবহারকারীর মাউসের অবস্থানের উপর ভিত্তি করে CSS কার্সার প্রপার্টি পরিবর্তন করা। যদি কার্সারটি গ্রিডের উপরে থাকে, আমরা এটিকে একটি হ্যান্ড কার্সারে স্যুইচ করি (কারণ তারা টোন তৈরি করে ইন্টারঅ্যাক্ট করতে পারে)। যদি এটি গ্রিডের চারপাশে হোয়াইটস্পেসে ঘোরা থাকে, তাহলে আমরা এটিকে একটি দিকনির্দেশক ক্রস কার্সারের জন্য অদলবদল করে দিই (তারা ঘোরাতে পারে বা গ্রিডকে স্তরে বিস্ফোরিত করতে পারে)।

শো-এর জন্য প্রস্তুত হচ্ছে

কম (একটি সিএসএস প্রি-প্রসেসর), এবং কোডকিট (স্টেরয়েডের উপর ওয়েব ডেভেলপমেন্ট) ডিজাইন ফাইলগুলিকে এইচটিএমএল/সিএসএসে অনুবাদ করতে যে সময় লেগেছিল তা সত্যিই কমিয়ে দিয়েছে। এগুলি আমাদেরকে আরও বহুমুখী ফ্যাশনে সিএসএসকে সংগঠিত, লিখতে এবং অপ্টিমাইজ করতে দিন — লিভারেজিং ভেরিয়েবল, মিক্স-ইন (ফাংশন) এবং এমনকি গণিত!

পর্যায় প্রভাব

CSS3 ট্রানজিশন এবং backbone.js ব্যবহার করে আমরা কিছু সত্যিই সাধারণ প্রভাব তৈরি করেছি যা অ্যাপ্লিকেশনটিকে প্রাণবন্ত করতে সাহায্য করে এবং ব্যবহারকারীদের ভিজ্যুয়াল সারি প্রদান করে যা নির্দেশ করে যে তারা কোন যন্ত্র ব্যবহার করছে।

টেকনিটোনের রং।

Backbone.js আমাদের রঙ পরিবর্তন ইভেন্টগুলি ধরতে এবং উপযুক্ত DOM উপাদানগুলিতে নতুন রঙ প্রয়োগ করতে দেয়। GPU ত্বরান্বিত CSS3 রূপান্তরগুলি পারফরম্যান্সের উপর সামান্য-থেকে-কোন প্রভাব সহ রঙ শৈলী পরিবর্তনগুলি পরিচালনা করে।

ইন্টারফেস উপাদানগুলিতে বেশিরভাগ রঙের রূপান্তরগুলি পটভূমির রঙগুলি পরিবর্তন করে তৈরি করা হয়েছিল। এই পটভূমির রঙের উপরে, আমরা ব্যাকগ্রাউন্ডের ছবিগুলিকে স্বচ্ছতার কৌশলগত ক্ষেত্রগুলির সাথে রাখি যাতে পটভূমির রঙটি উজ্জ্বল হয়।

এইচটিএমএল: ফাউন্ডেশন

ডেমোর জন্য আমাদের তিনটি রঙের অঞ্চল প্রয়োজন: দুটি ব্যবহারকারী নির্বাচিত রঙ অঞ্চল এবং একটি তৃতীয় মিশ্র রঙ অঞ্চল। আমরা সবচেয়ে সহজ DOM স্ট্রাকচার তৈরি করেছি যা আমরা CSS3 ট্রানজিশন এবং আমাদের উদাহরণের জন্য সবচেয়ে কম HTTP অনুরোধের কথা ভাবতে পারি।

<!-- Basic HTML Setup -->
<div class="illo color-mixed">
  <div class="illo color-primary"></div>
  <div class="illo color-secondary"></div>
</div>

CSS: শৈলী সহ সাধারণ কাঠামো

আমরা প্রতিটি অঞ্চলকে তার সঠিক অবস্থানে রাখার জন্য পরম পজিশনিং ব্যবহার করেছি এবং প্রতিটি অঞ্চলের মধ্যে পটভূমি চিত্রটি সারিবদ্ধ করতে পটভূমি-অবস্থান বৈশিষ্ট্য সামঞ্জস্য করেছি। এটি সমস্ত অঞ্চলকে (প্রতিটি একই ব্যাকগ্রাউন্ড ইমেজ সহ), একটি একক উপাদানের মতো দেখায়।

.illo {
  background: url('../img/illo.png') no-repeat;
  top:        0;
  cursor:     pointer;
}
  .illo.color-primary, .illo.color-secondary {
    position: absolute;
    height:   100%;
  }
  .illo.color-primary {
    width:                350px;
    left:                 0;
    background-position:  top left;
  }
  .illo.color-secondary {
    width:                355px;
    right:                0;
    background-position:  top right;
  }

GPU ত্বরিত রূপান্তর প্রয়োগ করা হয়েছিল যা রঙ পরিবর্তন ইভেন্টগুলির জন্য শোনে। আমরা সময়কাল বাড়িয়েছি এবং .color-mixed-এ ইজিং পরিবর্তন করেছি যাতে এই ধারণা তৈরি হয় যে রঙগুলি মিশ্রিত হতে সময় লাগে।

/* Apply Transitions To Backgrounds */
.color-primary, .color-secondary {
  -webkit-transition: background .5s linear;
  -moz-transition:    background .5s linear;
  -ms-transition:     background .5s linear;
  -o-transition:      background .5s linear;
}

.color-mixed {
  position:           relative;
  width:              750px;
  height:             600px;
  -webkit-transition: background 1.5s cubic-bezier(.78,0,.53,1);
  -moz-transition:    background 1.5s cubic-bezier(.78,0,.53,1);
  -ms-transition:     background 1.5s cubic-bezier(.78,0,.53,1);
  -o-transition:      background 1.5s cubic-bezier(.78,0,.53,1);
}

বর্তমান ব্রাউজার সমর্থন এবং CSS3 ট্রানজিশনের জন্য প্রস্তাবিত ব্যবহারের জন্য দয়া করে HTML5-এ যান।

জাভাস্ক্রিপ্ট: এটি কাজ করে

গতিশীলভাবে রং বরাদ্দ করা সহজ। আমরা আমাদের রঙের শ্রেণী সহ যেকোনো উপাদানের জন্য DOM অনুসন্ধান করি এবং ব্যবহারকারীর রঙ নির্বাচনের উপর ভিত্তি করে ব্যাকগ্রাউন্ড-কালার সেট করি। আমরা একটি ক্লাস যোগ করে DOM-এর যেকোনো উপাদানে আমাদের ট্রানজিশন প্রভাব প্রয়োগ করি। এটি একটি স্থাপত্য তৈরি করে যা হালকা, নমনীয় এবং মাপযোগ্য।

function createPotion() {

    var primaryColor = $('.picker.color-primary > li.selected').css('background-color');
    var secondaryColor = $('.picker.color-secondary > li.selected').css('background-color');
    console.log(primaryColor, secondaryColor);
    $('.illo.color-primary').css('background-color', primaryColor);
    $('.illo.color-secondary').css('background-color', secondaryColor);

    var mixedColor = mixColors (
            parseColor(primaryColor),
            parseColor(secondaryColor)
    );

    $('.color-mixed').css('background-color', mixedColor);
}

একবার প্রাথমিক এবং মাধ্যমিক রং নির্বাচন করা হলে, আমরা তাদের মিশ্র রঙের মান গণনা করি এবং উপযুক্ত DOM উপাদানের জন্য ফলস্বরূপ মান নির্ধারণ করি।

// take our rgb(x,x,x) value and return an array of numeric values
function parseColor(value) {
    return (
            (value = value.match(/(\d+),\s*(\d+),\s*(\d+)/)))
            ? [value[1], value[2], value[3]]
            : [0,0,0];
}

// blend two rgb arrays into a single value
function mixColors(primary, secondary) {

    var r = Math.round( (primary[0] * .5) + (secondary[0] * .5) );
    var g = Math.round( (primary[1] * .5) + (secondary[1] * .5) );
    var b = Math.round( (primary[2] * .5) + (secondary[2] * .5) );

    return 'rgb('+r+', '+g+', '+b+')';
}

এইচটিএমএল/সিএসএস আর্কিটেকচারের জন্য ইলাস্ট্রেটিং: তিনটি কালার শিফটিং বক্সের ব্যক্তিত্ব দেওয়া

আমাদের লক্ষ্য ছিল একটি মজাদার এবং বাস্তবসম্মত আলোক প্রভাব তৈরি করা যা এর অখণ্ডতা বজায় রাখে যখন পার্শ্ববর্তী রঙের অঞ্চলে বিপরীত রঙগুলি স্থাপন করা হয়।

একটি 24-বিট PNG আমাদের এইচটিএমএল উপাদানগুলির পটভূমি-রঙকে চিত্রের স্বচ্ছ অঞ্চলগুলির মাধ্যমে দেখানোর অনুমতি দেয়।

ছবির স্বচ্ছতা

রঙিন বাক্সগুলি শক্ত প্রান্ত তৈরি করে যেখানে বিভিন্ন রঙ মিলিত হয়। এটি বাস্তবসম্মত আলোক প্রভাবের পথে পায় এবং চিত্রটি ডিজাইন করার সময় এটি একটি বড় চ্যালেঞ্জ ছিল।

রঙ অঞ্চল

সমাধানটি ছিল চিত্রটি এমনভাবে ডিজাইন করা যাতে এটি কখনই রঙিন অঞ্চলের প্রান্তগুলিকে স্বচ্ছ এলাকার মাধ্যমে দেখানোর অনুমতি দেয় না।

রঙ অঞ্চল প্রান্ত

নির্মাণের জন্য পরিকল্পনা সমালোচনামূলক ছিল. ডিজাইনার, ডেভেলপার এবং ইলাস্ট্রেটরের মধ্যে একটি দ্রুত পরিকল্পনা সেশন টিমকে বুঝতে সাহায্য করেছে যে কীভাবে সবকিছু তৈরি করা দরকার তাই এটি একত্রিত হলে একসাথে কাজ করবে।

লেয়ার নামকরণ কীভাবে CSS নির্মাণ সম্পর্কে তথ্য যোগাযোগ করতে পারে তার উদাহরণ হিসাবে ফটোশপ ফাইলটি দেখুন।

রঙ অঞ্চল প্রান্ত

এনকোর

ক্রোম ছাড়া ব্যবহারকারীদের জন্য, আমরা একটি একক স্ট্যাটিক ইমেজে অ্যাপ্লিকেশনটির সারাংশ পাতন করার লক্ষ্য নির্ধারণ করেছি। গ্রিড নোডটি হিরো হয়ে উঠেছে, ব্যাকগ্রাউন্ড টাইলসগুলি অ্যাপ্লিকেশনের উদ্দেশ্যকে নির্দেশ করে এবং প্রতিফলনে উপস্থিত দৃষ্টিকোণ গ্রিডের নিমজ্জিত 3D পরিবেশে ইঙ্গিত দেয়।

রঙ অঞ্চল প্রান্ত.

আপনি যদি টেকনিটোন সম্পর্কে আরও জানতে আগ্রহী হন তবে আমাদের ব্লগে থাকুন।

দল

পড়ার জন্য ধন্যবাদ, সম্ভবত আমরা শীঘ্রই আপনার সাথে জ্যাম করব!