660 karma · joined September 14, 2010
my token usage: tkmx.odio.dev/user/jmfd
We get maybe 2-3 requests a week for Hype on Windows. My napkin math estimates of potential customers (those that don't write in or saw our FAQ, and then would go on to buy) shows this might lead to lower double-digit percent income coming from a Windows port. This roughly corresponds with our site traffic, which is 18% Windows users.
My general thought is (at this time) we’d do better to develop enticing new features to expand our user base than doing a Windows/web port.
When we started out Adobe was still sticking to their Flash guns. As HTML5 was the only method to make animated web content on iOS, it was clear someone needed to make tools aimed at graphic designers, so we decided that someone should be us! Luckily with no other competing apps around, we didn't have to deal with an uphill battle on feature parity unlike these vector editors do with Illustrator. So I wouldn't say we were disgruntled, just trying to fill in a hole. And, on a personal note I had a need for such a tool for a side project I was working on.
OS X is a great platform to develop for generally speaking. We naturally leverage WebKit, and Quartz and CoreImage frameworks I'm sure do a lot of heavy lifting for the vector-based tools. Also keep in mind a larger percent of graphic pros use a Mac than the general population, so if you're building a tool it is a safe bet to start on the Mac.
How do you define an average user anyhow? I think there's only more common use cases. Everyone has their special needs and uses on the internet.
In your example, wouldn't the "BC" be the domain name and not "Starbucks?" I don't know if there's any way to know with certainty in all URLs whether the domain name or the path components are more important to a user.
We've moved nearly all of our other videos to youtube, so if it really is our server you can click the "watch more" buttons on the main page to still get a feel for the app.
While Google hasn't announced pricing, it is probably safe to say it is going to be free. This is a business for us, so we charge $29.99. I don't like competing against free, but that just means we'll be continually pushed to provide that much more value!
There hasn't been much that's swayed us otherwise -- I think it was the right call.
http://arstechnica.com/information-technology/2012/07/ninja-...
http://arstechnica.com/information-technology/2012/07/ninja-...
While everything has its tradeoffs, we went with this approach because:
- Our app has a lot of animation and interactivity capabilities not meaningfully expressed through anything but JavaScript. For example, we don't use CSS3 Animations nor transitions because they aren't powerful enough (pausing, synchronization, etc.).
- We have better control over how we express the DOM to the browser. There's plenty of browser bugs or incompatibilities which sometimes require us to on-the-fly change the DOM structure or which properties we are using.
- The user could easily bork the output so it could not be read back in
- No tool will ever produce output that will appease everyone :)
We provide lots of hooks in and outside of the runtime for your own JavaScript and HTML so you can still customize quite a bit.
So it isn't that our output isn't very clean (in fact I'm quite proud of the runtime and how we've been able to add features without increasing bloat); it is that edits are meant to happen from the app itself.
Sandboxing was a technology that did not exist (and therefore was not required) when we started selling on the Mac App Store. This came later, and became a requirement to push any updates containing features.
Lots of mac developers have complained publicly (or privately to me) about sandboxing. Many others have not been able to issue updates, removed major features, or simply removed their apps from the store. There's plenty of information on this on blogs or the developer forums, though many would not speak out publicly against the hand that feeds them. The apps that do well with sandboxing are naturally those which do the least. It would have been easier for us to neuter our app, but we've taken a strong approach to working through all the issues and avoided removing any major features. It would be unfortunate if innovation was sacrificed for security.
We originally planned to have our non-MAS copy not be sandboxed. This creates complications and other bugs for users when offering both versions based on how the sandbox container is maintained and that any bookmarks (aliases) kept cannot interoperate between the two. From all the tradeoffs we see, fully adopting sandboxing is the best option. But, that won't stop me from complaining about all the bugs!
I wrote it up as more of a public service announcement to other Mac developers who might be encountering the same issue.
Besides, is it really obvious that top/left would be faster (in a non-transition case)? It requires an additional layout phase compared to transforms:translate().
On the common sense of transitions being faster, it is true that there will be overhead in running JavaScript code. But at the same time, 1/60th of a second is a very long time for a computer and (for me) the overhead of crossing the bridge and running a minimal amount of JavaScript was an unknown.
Being from the "show me state" I like to measure before doing any performance optimization work or making general claims.
However, if you do "naturally gravitate to product management" -- that is you find yourself in those roles or have been assigned to those roles without effort or conscious action -- then it is a good sign of fit.
- If the bug is a regression it may stem from the author's misunderstanding of the codebase. By being the one to fix the bug they have a chance to learn correctly how it works and reduce future mistakes.
- The original author of the bug was just in the code and can likely most efficiently fix it since they are recently familiar.
- It would be wasteful to have two people working on the bug at the same time (though bug policy can also help with this).
- On a large project there can be lots of noise which does not affect you, especially if the project is well compartmentalized.
- Taking responsibility is always a good thing!
It is only toxic when people start pointing fingers and shifting blame instead of helping out. As a "component owner," I personally like to fix my own mistakes so I can learn from them.
My best recommendation is to always use Google Closure Compiler. By default it doesn't work much better than other minifiers, but there's an --compilation_level ADVANCED_OPTIMIZATIONS flag that can have a dramatic result. To use this, it is likely you'll have to structure your code differently and make sure exports work correctly, but we were able to take reduce a further 50% with this one change. In this release, we also changed a few other flags (in the code itself; there are no command line settings) which we thought would be advantageous to our file and userbase.
We also do a lot of string replacements. I built a simple templating system that glues files together and also can replace descriptive, programmer-friendly, key names with single letter variables. Strings can weigh a lot. In this release in particular, I also looked at the minified JS and examined which strings could be partially combined. For example, "rotateY(0deg)" and "rotateY(10deg)" could both have the "rotateY(" extracted and save some bytes. It matters less if you're using gzip compression, but we can't guarantee that among our users. The key is to make sure this doesn't make the code hard to read or edit in the future, and only tackle the most significant changes.
Not quite related to the HYPE.js runtime, but we also focused on reducing the entire export data size, including the JSON animation info. We again used a lot of string substitution -- "startTime" and "duration" in code simply become "s" and "d". With JSON, depending on the key name you might also not need quotes around them, so for an animation object it could be {s:1.2,d:3}. The quote characters can add up! There's lot of other things we did such as not exporting the common/default values since we could figure this out if the key does not exist, and being smart about element id's so they would not be some long UUID.
With this, they could potentially send out notifications to just their audience when participation would be useful. Completing tasks could also be a micropayment allowing the developer to give the user some sort of reward (like unlocking bonus features).
- Memory management model (ARC, GC, or refcount)
- Min/Max OS X version or SDK
- If it is sandboxable
It'd also be fun to see a list of projects which use the controls.
NSCountedSet - and NSMutableSet that keeps counts of objects added
NSValueTransformer - More of a design pattern for generically converting objects
NSArgumentDomain in NSUserDefaults - command line arguments of -key value become user defaults
NSXMLNode nodesForXPath:error:/objectsForXQuery:error: - run XPath or XQuery against XML... even better, subclass NSXMLNode and then use XPath and XQuery on any hierarchical data you have
NSObject's performSelectorOnMainThread:withObject:waitUntilDone: - use NO for waitUntilDone and the method will be called at the end of the event loop (I've seen many people use the afterDelay variant instead)
NSNotificationQueue - use NSNotificationCoalescingOnName to batch up NSNotifications to send a single one at the end of the event loop, though there's lots of gotchyas for using it correctly
NSOrthography - Okay, even I didn't know about this before re-glancing at the foundation reference :)
I also believe API should go through a feedback/review processes with peers. Other developers will have used different patterns, have a different base of experience with the platform, and can generally help find common mistakes. So, here's some of my feedback/nitpicks on MGTileMenuController.h :) --
@property (nonatomic, weak, readonly) id<MGTileMenuDelegate> delegate; // must be specified via initializer method.
- (id)initWithDelegate:(id<MGTileMenuDelegate>)theDelegate;
It is very rare for delegates to be required for initialization, and I don't see why the @property for the delegate needs to be readonly? Perhaps an owner would be a better model?The isVisible property looks like this:
@property (nonatomic, readonly) BOOL isVisible;
But typically for BOOLs the property is the normal form with a specific "is" getter: @property(nonatomic,readonly,getter=isVisible) BOOL visible;
// N.B. All of the following properties should be set BEFORE displaying the menu.
This makes me wonder what happens if I want to change them later? It seems that they should always be able to be changed, and in general comments shouldn't be required to understand library behavior as they'll just be missed by developers anyways. - (NSInteger)nextPageNumber:(NSInteger)currentPageNumber; // zero-based pageNumber
Why would the nextPageNumber not be +1 from currentPageNumber? Also, why do I need to supply a currentPageNumber when it appears currentPage is a @property of the class? Is there a difference between "currentPage" and "currentPageNumber" as their naming indicates there might be one? Also, it might be better to name the method similar to the NSIndexSet convention "indexGreaterThanIndex." Should an NSIndexSet actually be used instead? - (UIBezierPath *)_bezelPath;
This method looks like it is private/internal because of a leading underscore, so it shouldn't be exposed in the header. Also, Apple has reserved naming methods with a leading underscore (especially important when you are subclassing!). https://developer.apple.com/library/mac/#documentation/Cocoa...In general, if the developer doesn't need the utilities, I highly question adding them to the header since you'll be responsible for them for all time.
Finally, why not add the delegate protocol to the header file so everything is consolidated for the developer using the class?